Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added commission settings sub-categories reset toggle. #2543

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 42 additions & 7 deletions assets/src/js/setup-wizard/commission/AdminCommission.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,20 @@
</div>
</div>
<div v-if="'category_based' === selectedCommission">
<p class="!p-0 !m-0 !font-semibold" for="_subscription_product_admin_commission_type">{{__( 'Admin Commission', 'dokan-lite' )}}</p>
<category-based-commission
:value="commission"
@change="onCategoryUpdate"
/>
<div class="flex justify-between mb-4 !p-0 m-0">
<label class="!p-0 m-0 !mb-[6px] block" for="_subscription_product_admin_commission_type">
{{__( 'Apply Parent Category Commission to All Subcategories ', 'dokan-lite' )}}
</label>
<Switches @input="handleResetToggle" :enabled="resetSubCategory"/>
</div>
<div class="!p-0 !m-0">
<p class="!font-semibold" for="_subscription_product_admin_commission_type">{{__( 'Admin Commission', 'dokan-lite' )}}</p>
<category-based-commission
:value="commission"
@change="onCategoryUpdate"
:resetSubCategory="resetSubCategory"
/>
</div>
</div>
<div v-else-if="'fixed' === selectedCommission">
<p class="!p-0 !m-0 !font-semibold" for="_subscription_product_admin_commission_type">{{__( 'Admin Commission', 'dokan-lite' )}}</p>
Expand All @@ -27,28 +36,31 @@
<input type="hidden" :value="fixedCommission.fixed ?? 0" name="dokan_commission_flat">
<input type="hidden" :value="fixedCommission.percentage ?? 0" name="dokan_commission_percentage">
<input type="hidden" :value="JSON.stringify(commission)" name="dokan_commission_category_based">
<input type="hidden" :value="resetSubCategory" name="reset_sub_category">
</div>
</template>

<script>
import CategoryBasedCommission from "admin/components/Commission/CategoryBasedCommission.vue";
import CombineInput from "admin/components/CombineInput.vue";
import Switches from "../../../../../src/admin/components/Switches.vue";

export default {
name: 'AdminCommission',

components: { CategoryBasedCommission, CombineInput },
components: { Switches, CategoryBasedCommission, CombineInput },

data() {
return {
selectedCommission: 'fixed',
commission: {},
commissionTypes: {},
fixedCommission: {},
resetSubCategory: true
}
},

created() {
mounted() {
let element = document.getElementById( 'dokan-setup-wizard-commission-data' );

if ( ! element || ! element.dataset || ! element.dataset.commission ) {
Expand All @@ -67,9 +79,32 @@
commission_category_based_values.items = ! commission_category_based_values.items || Array.isArray( commission_category_based_values.items ) ? {} : commission_category_based_values.items;

this.commission = commission_category_based_values;
this.resetSubCategory = commission.reset_sub_category ?? true;
},

methods: {
handleResetToggle(value) {
const confirmTitle = value ? this.__("Enable Commission Inheritance Setting?", "dokan-lite") : this.__("Disable Commission Inheritance Setting?", "dokan-lite");
const htmlText = value ? this.__("Parent category commission changes will automatically update all subcategories. Existing rates will remain unchanged until parent category is modified.", "dokan-lite") : this.__("Subcategories will maintain their independent commission rates when parent category rates are changed.", "dokan-lite");
const confirmBtnText = value ? this.__("Enable", "dokan-lite") : this.__("Disable", "dokan-lite");
const updatableValue = !value;
const self = this;

Swal.fire({
icon: "warning",
html: htmlText,
title: confirmTitle,
showCancelButton: true,
cancelButtonText: this.__("Cancel", "dokan-lite"),
confirmButtonText: confirmBtnText
}).then((response) => {
const status = response.isConfirmed ? value : updatableValue;
self.resetSubCategory = status;

self.vendorInfo.reset_sub_category = status;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

vendorInfo is undefined and needs proper declaration

After thorough verification, vendorInfo is not defined in the component's:

  • data properties
  • props
  • mixins
  • explicit assignments

This confirms the original review comment. The use of an undefined vendorInfo in a callback could lead to runtime errors.

Recommendations:

  • Declare vendorInfo in the component's data() if it's local state
  • Add it to props if it's passed from a parent component
  • Document any global state management if that's the intended source
🔗 Analysis chain

Verify vendorInfo reference.

The vendorInfo object is referenced but not defined in the component's data or props. This could lead to runtime errors.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for vendorInfo definition in related files
rg -A 5 "vendorInfo.*=|data\(\).*{" assets/src/js/setup-wizard/commission/

Length of output: 190


Script:

#!/bin/bash
# Search for vendorInfo in data, props, and imports
echo "=== Searching for vendorInfo in data() ==="
rg "data\s*\(\)\s*\{" -A 10 "assets/src/js/setup-wizard/commission/AdminCommission.vue"

echo -e "\n=== Searching for vendorInfo assignment or props ==="
rg "vendorInfo|props\s*:\s*\{" -A 5 "assets/src/js/setup-wizard/commission/AdminCommission.vue"

echo -e "\n=== Checking imports and component registration ==="
rg "import.*from|components\s*:\s*\{" -A 3 "assets/src/js/setup-wizard/commission/AdminCommission.vue"

Length of output: 1485


Script:

#!/bin/bash
# Search for mixins and vendorInfo assignments
echo "=== Checking for mixins and vendorInfo assignments ==="
rg "mixins|this\.vendorInfo\s*=|self\.vendorInfo\s*=" -A 5 "assets/src/js/setup-wizard/commission/AdminCommission.vue"

echo -e "\n=== Checking imported components for vendorInfo ==="
rg -g "*.vue" "vendorInfo" "admin/components/Commission/"

Length of output: 481

});
},

onCategoryUpdate(data) {
this.commission = data;
},
Expand Down
8 changes: 8 additions & 0 deletions includes/Admin/Settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,14 @@ public function get_settings_fields() {
],
],
],
'reset_sub_category_when_edit_all_category' => [
'name' => 'reset_sub_category_when_edit_all_category',
'label' => __( 'Apply Parent Category Commission to All Subcategories', 'dokan-lite' ),
'desc' => __( 'Important: \'All Categories\' commission serves as your marketplace\'s default rate and cannot be empty. If 0 is given in value, then the marketplace will deduct no commission from vendors', 'dokan-lite' ),
'type' => 'switcher',
'default' => 'on',
'tooltip' => __( 'When enabled, changing a parent category\'s commission rate will automatically update all its subscription. Disable this option to maintain independent commission rates for subcategories', 'dokan-lite' ),
],
'commission_category_based_values' => [
'name' => 'commission_category_based_values',
'type' => 'category_based_commission',
Expand Down
16 changes: 10 additions & 6 deletions includes/Admin/SetupWizard.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public function enqueue_scripts() {
wp_enqueue_script(
'dokan-setup-wizard-commission',
DOKAN_PLUGIN_ASSEST . '/js/dokan-setup-wizard-commission.js',
array( 'jquery', 'dokan-vue-bootstrap', 'dokan-accounting' ),
array( 'jquery', 'dokan-vue-bootstrap', 'dokan-accounting', 'dokan-sweetalert2' ),
DOKAN_PLUGIN_VERSION,
[ 'in_footer' => true ]
);
Expand Down Expand Up @@ -517,6 +517,8 @@ public function dokan_setup_commission() {
$additional_fee = isset( $options['additional_fee'] ) ? $options['additional_fee'] : 0;
$commission_category_based_values = isset( $options['commission_category_based_values'] ) ? $options['commission_category_based_values'] : new stdClass();
$commission_type = ! empty( $options['commission_type'] ) ? $options['commission_type'] : 'fixed';
$reset_sub_category_when_edit_all_category = ! empty( $options['reset_sub_category_when_edit_all_category'] ) ? $options['reset_sub_category_when_edit_all_category'] : 'on';
$reset_sub_category = ! ( $reset_sub_category_when_edit_all_category === 'off' );

$args = apply_filters(
'dokan_admin_setup_wizard_step_setup_selling_template_args', [
Expand All @@ -525,6 +527,7 @@ public function dokan_setup_commission() {
'additional_fee' => $additional_fee,
'commission_category_based_values' => $commission_category_based_values,
'dokanCommission' => dokan_commission_types(),
'reset_sub_category' => $reset_sub_category,
'setup_wizard' => $this,
]
);
Expand Down Expand Up @@ -565,11 +568,12 @@ public function dokan_setup_commission_save() {
$dokan_commission_percentage = 0;
}

$options = get_option( 'dokan_selling', [] );
$options['commission_type'] = isset( $_POST['dokan_commission_type'] ) ? sanitize_text_field( wp_unslash( $_POST['dokan_commission_type'] ) ) : 'fixed';
$options['admin_percentage'] = $dokan_commission_percentage;
$options['additional_fee'] = isset( $_POST['dokan_commission_flat'] ) ? sanitize_text_field( wp_unslash( $_POST['dokan_commission_flat'] ) ) : 0;
$options['commission_category_based_values'] = isset( $_POST['dokan_commission_category_based'] ) ? wc_clean( json_decode( sanitize_text_field( wp_unslash( $_POST['dokan_commission_category_based'] ) ), true ) ) : [];
$options = get_option( 'dokan_selling', [] );
$options['commission_type'] = isset( $_POST['dokan_commission_type'] ) ? sanitize_text_field( wp_unslash( $_POST['dokan_commission_type'] ) ) : 'fixed';
$options['admin_percentage'] = $dokan_commission_percentage;
$options['additional_fee'] = isset( $_POST['dokan_commission_flat'] ) ? sanitize_text_field( wp_unslash( $_POST['dokan_commission_flat'] ) ) : 0;
$options['commission_category_based_values'] = isset( $_POST['dokan_commission_category_based'] ) ? wc_clean( json_decode( sanitize_text_field( wp_unslash( $_POST['dokan_commission_category_based'] ) ), true ) ) : [];
$options['reset_sub_category_when_edit_all_category'] = isset( $_POST['reset_sub_category'] ) && false === dokan_string_to_bool( $_POST['reset_sub_category'] ) ? 'off' : 'on';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Sanitize POST data before use.

The reset_sub_category POST value is not properly sanitized before use, which could lead to security issues.

-        $options['reset_sub_category_when_edit_all_category'] = isset( $_POST['reset_sub_category'] ) && false === dokan_string_to_bool( $_POST['reset_sub_category'] ) ? 'off' : 'on';
+        $options['reset_sub_category_when_edit_all_category'] = isset( $_POST['reset_sub_category'] ) && false === dokan_string_to_bool( sanitize_text_field( wp_unslash( $_POST['reset_sub_category'] ) ) ) ? 'off' : 'on';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$options['reset_sub_category_when_edit_all_category'] = isset( $_POST['reset_sub_category'] ) && false === dokan_string_to_bool( $_POST['reset_sub_category'] ) ? 'off' : 'on';
$options['reset_sub_category_when_edit_all_category'] = isset( $_POST['reset_sub_category'] ) && false === dokan_string_to_bool( sanitize_text_field( wp_unslash( $_POST['reset_sub_category'] ) ) ) ? 'off' : 'on';
🧰 Tools
🪛 GitHub Actions: Inspections

[error] 576-576: Security issue: $_POST['reset_sub_category'] not unslashed and not sanitized before use


update_option( 'dokan_selling', $options );

Expand Down
6 changes: 6 additions & 0 deletions includes/Vendor/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,12 @@ public function update( $vendor_id, $data = [] ) {
$vendor->update_meta( 'dokan_publishing', 'no' );
}

if ( isset( $data['reset_sub_category'] ) && dokan_validate_boolean( $data['reset_sub_category'] ) ) {
$vendor->update_meta( 'reset_sub_category', 'yes' );
} else {
$vendor->update_meta( 'reset_sub_category', 'no' );
}

if ( ! empty( $data['admin_commission_type'] ) ) {
$vendor->update_meta( 'dokan_admin_percentage_type', $data['admin_commission_type'] );
}
Expand Down
10 changes: 10 additions & 0 deletions includes/Vendor/Vendor.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ public function to_array() {
'registered' => $this->get_register_date(),
'payment' => $this->get_payment_profiles(),
'trusted' => $this->is_trusted(),
'reset_sub_category' => $this->get_reset_sub_category(),
'store_open_close' => [
'enabled' => $this->is_store_time_enabled(),
'time' => $this->get_store_time(),
Expand Down Expand Up @@ -215,6 +216,15 @@ public function is_featured() {
return 'yes' == get_user_meta( $this->id, 'dokan_feature_seller', true );
}

/**
* If reset sub category is enabled
*
* @return boolean
*/
public function get_reset_sub_category() {
return 'no' !== get_user_meta( $this->id, 'reset_sub_category', true );
}

/**
* Populate store info
*
Expand Down
20 changes: 17 additions & 3 deletions src/admin/components/Commission/CategoryBasedCommission.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
<div class='d-xs:flex h-1/2'>
<span v-for='parent_id in item.parents' :key='parent_id' class='d-xs:bg-[#e5e7eb] md:bg-transparent block h-full w-[1px] d-xs:ml-1'></span>
</div>
<button type='button' class='p-1 d-xs:pl-1 md:pl-6 bg-transparent border-none cursor-pointer' :disabled='!item.children.length' :class='!item.children.length ? "disabled:cursor-not-allowed text-gray-300" : "cursor-pointer text-[#F05025]"' @click='()=> catRowClick( item, index )'>
<button type='button' class='p-1 d-xs:pl-1 md:pl-6 bg-transparent border-none cursor-pointer' :disabled='!item.children.length' :class='!item.children.length ? "disabled:cursor-not-allowed text-gray-300" : "cursor-pointer text-[#4C19E6]"' @click='()=> catRowClick( item, index )'>
<i class="far" :class='openRows.includes( Number( item.term_id ) ) ? "fa-minus-square text-black" : "fa-plus-square"'></i>
</button>
<p class='d-xs:text-[8px] sm:text-[14px] text-black !m-0'>
Expand Down Expand Up @@ -122,6 +122,10 @@
},
items:{}
}
},
resetSubCategory: {
type: Boolean,
default: true
}
},
computed: {
Expand Down Expand Up @@ -266,7 +270,10 @@

let commissions = JSON.parse( JSON.stringify( this.commission.items ) );

let data = JSON.parse( JSON.stringify( this.commission.all ) );
let data = this.resetSubCategory ? JSON.parse( JSON.stringify( this.commission.all ) ) : {
flat: '',
percentage: ''
};

if ( commissions.hasOwnProperty( term_id ) ) {
data = commissions[term_id];
Expand All @@ -293,7 +300,10 @@
value = this.unFormatValue( value );
}
this.$set( this.commission.all, commission_type, value );
this.$set(this.commission, 'items', {});

let items = JSON.parse( JSON.stringify( this.commission.items ?? {} ) );
items = this.resetSubCategory ? {} : items;
this.$set(this.commission, 'items', items);

this.emitComponentChange( JSON.parse( JSON.stringify( this.commission ) ) )
}, 700 ),
Expand Down Expand Up @@ -356,6 +366,10 @@
},

updateChildCommissionValues(parent_cat_id, commission_data) {
if ( ! this.resetSubCategory ) {
return;
}

let all_nested_children_ids = this.getChildren( parent_cat_id );
let children = JSON.parse( JSON.stringify( this.commission.items ) );

Expand Down
1 change: 1 addition & 0 deletions src/admin/components/Fields.vue
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
<category-based-commission
:value="watchCategoryCommission"
@change="onCategoryUpdate"
:resetSubCategory="fieldValue?.reset_sub_category_when_edit_all_category && fieldValue?.reset_sub_category_when_edit_all_category === 'on'"
/>
</div>

Expand Down
41 changes: 40 additions & 1 deletion src/admin/components/VendorCommissionFields.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@
<span class="description !mt-[6px] block">{{__( 'Set the commission type that admin will get', 'dokan-lite' )}}</span>
</div>
</div>
<div v-if="'category_based' === selectedCommission" class="flex justify-between mb-4">
<label class="!p-0 m-0 !mb-[6px] block" for="_subscription_product_admin_commission_type">
{{__( 'Apply Parent Category Commission to All Subcategories ', 'dokan-lite' )}}

<span class="dokan-tooltips-help tips" v-tooltip :title="__( 'When enabled, changing a parent category\'s commission rate will automatically update all its subscription. Disable this option to maintain independent commission rates for subcategories', 'dokan-lite' )">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

subscription might be typo?

<i class="fas fa-question-circle"></i>
</span>
</label>
<Switches @input="handleResetToggle" :enabled="resetSubCategory"/>
</div>
<div v-if="'category_based' === selectedCommission">
<label class="!p-0 m-0 !mb-[6px] block" for="_subscription_product_admin_commission_type">
{{__( 'Admin Commission', 'dokan-lite' )}}
Expand All @@ -26,6 +36,7 @@
<category-based-commission
:value="categoryCommission"
@change="onCategoryUpdate"
:resetSubCategory="resetSubCategory"
/>
</div>
<div v-else-if="'fixed' === selectedCommission">
Expand All @@ -50,11 +61,12 @@

import CombineInput from "admin/components/CombineInput.vue";
import CategoryBasedCommission from "admin/components/Commission/CategoryBasedCommission.vue";
import Switches from "./Switches.vue";

export default {
name: "VendorCommissionFields",

components: { CategoryBasedCommission, CombineInput },
components: { Switches, CategoryBasedCommission, CombineInput },

props: {
vendorInfo: {
Expand All @@ -68,6 +80,7 @@ export default {
categoryCommission: {},
commissionTypes: {},
fixedCommission: {},
resetSubCategory: true
};
},

Expand All @@ -94,10 +107,36 @@ export default {
this.categoryCommission = this.vendorInfo.admin_category_commission;
}


if ( this.vendorInfo.hasOwnProperty( 'reset_sub_category' ) ) {
this.resetSubCategory = this.vendorInfo.reset_sub_category !== false;
}

this.fixedCommission = fixedCommission;
},

methods: {
handleResetToggle(value) {
const confirmTitle = value ? this.__("Enable Commission Inheritance Setting?", "dokan-lite") : this.__("Disable Commission Inheritance Setting?", "dokan-lite");
const htmlText = value ? this.__("Parent category commission changes will automatically update all subcategories. Existing rates will remain unchanged until parent category is modified.", "dokan-lite") : this.__("Subcategories will maintain their independent commission rates when parent category rates are changed.", "dokan-lite");
const confirmBtnText = value ? this.__("Enable", "dokan-lite") : this.__("Disable", "dokan-lite");
const updatableValue = !value;
const self = this;

Swal.fire({
icon: "warning",
html: htmlText,
title: confirmTitle,
showCancelButton: true,
cancelButtonText: this.__("Cancel", "dokan-lite"),
confirmButtonText: confirmBtnText
}).then((response) => {
const status = response.isConfirmed ? value : updatableValue;
self.resetSubCategory = status;

self.vendorInfo.reset_sub_category = status;
});
},
fixedCOmmissionhandler(data) {
if (isNaN( data.fixed )) {
data.fixed = this.fixedCommission.fixed ?? '';
Expand Down
21 changes: 21 additions & 0 deletions src/admin/pages/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,27 @@
}
});
}

if ( ( 'dokan_selling' in this.settingValues ) && 'reset_sub_category_when_edit_all_category' === fieldName ) {
const confirmTitle = 'on' === value ? this.__( 'Enable Commission Inheritance Setting?', 'dokan-lite' ) : this.__( 'Disable Commission Inheritance Setting?', 'dokan-lite' );
const htmlText = 'on' === value ? this.__( 'Parent category commission changes will automatically update all subcategories. Existing rates will remain unchanged until parent category is modified.', 'dokan-lite' ) : this.__( 'Subcategories will maintain their independent commission rates when parent category rates are changed.', 'dokan-lite' );
const confirmBtnText = 'on' === value ? this.__( 'Enable', 'dokan-lite' ) : this.__( 'Disable', 'dokan-lite' );
const updatableValue = 'on' === value ? 'off' : 'on';

Swal.fire({
icon : 'warning',
html : htmlText,
title : confirmTitle,
showCancelButton : true,
cancelButtonText : this.__( 'Cancel', 'dokan-lite' ),
confirmButtonText : confirmBtnText,
}).then( ( response ) => {
if ( response.dismiss ) {
this.settingValues.dokan_selling.reset_sub_category_when_edit_all_category = updatableValue;
this.$emit( 'switcHandler', 'reset_sub_category_when_edit_all_category', this.settingValues.dokan_selling.reset_sub_category_when_edit_all_category );
}
});
}
});

// Scroll into specific setting field.
Expand Down
Loading
Loading