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

Fix decimal and thousand separator for category commission. #2440

Merged
merged 14 commits into from
Nov 26, 2024
Merged
7 changes: 6 additions & 1 deletion assets/src/js/setup-wizard/commission/AdminCommission.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,12 @@
this.fixedCommission.fixed = commission.additional_fee ? Number( commission.additional_fee ) : 0;
this.fixedCommission.percentage = commission.admin_percentage ? Number( commission.admin_percentage ) : 0;
this.selectedCommission = commission.commission_type ? String(commission.commission_type) : 'fixed';
this.commission = commission.commission_category_based_values;
let commission_category_based_values = commission.commission_category_based_values;

commission_category_based_values.all = ! commission_category_based_values.all || Array.isArray( commission_category_based_values.all ) ? {} : commission_category_based_values.all;
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;
Comment on lines +64 to +69
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

Strengthen data validation and initialization.

The current initialization logic has several potential issues:

  1. Loose comparisons might not catch all edge cases
  2. No validation for commission percentage ranges
  3. No handling for decimal/thousand separators

Consider applying these improvements:

-            let commission_category_based_values = commission.commission_category_based_values;
+            let commission_category_based_values = commission.commission_category_based_values || {};
 
-            commission_category_based_values.all = ! commission_category_based_values.all || Array.isArray( commission_category_based_values.all ) ? {} : commission_category_based_values.all;
-            commission_category_based_values.items = ! commission_category_based_values.items || Array.isArray( commission_category_based_values.items ) ? {} : commission_category_based_values.items;
+            // Ensure proper object initialization
+            commission_category_based_values.all = (typeof commission_category_based_values.all === 'object' && !Array.isArray(commission_category_based_values.all)) 
+                ? commission_category_based_values.all 
+                : {};
+            commission_category_based_values.items = (typeof commission_category_based_values.items === 'object' && !Array.isArray(commission_category_based_values.items)) 
+                ? commission_category_based_values.items 
+                : {};
+
+            // Validate commission percentages
+            Object.keys(commission_category_based_values.all).forEach(key => {
+                const value = parseFloat(commission_category_based_values.all[key]);
+                if (isNaN(value) || value < 0 || value > 100) {
+                    commission_category_based_values.all[key] = 0;
+                }
+            });

Committable suggestion skipped: line range outside the PR's diff.

},

methods: {
Expand Down
11 changes: 6 additions & 5 deletions includes/Admin/Settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -538,12 +538,13 @@ public function get_settings_fields() {
],
],
'commission_category_based_values' => [
'name' => 'commission_category_based_values',
'type' => 'category_based_commission',
'name' => 'commission_category_based_values',
'type' => 'category_based_commission',
'dokan_pro_commission' => 'yes',
'label' => __( 'Admin Commission', 'dokan-lite' ),
'desc' => __( 'Amount you will get from each sale', 'dokan-lite' ),
'show_if' => [
'label' => __( 'Admin Commission', 'dokan-lite' ),
'desc' => __( 'Amount you will get from each sale', 'dokan-lite' ),
'required' => 'yes',
'show_if' => [
'commission_type' => [
'equal' => 'category_based',
],
Expand Down
10 changes: 9 additions & 1 deletion includes/Commission.php
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,15 @@ public function get_commission( $args = [], $auto_save = false ) {
$category_id = $category_id ? $category_id : 0;
}

if ( ! empty( $product_id ) && empty( $total_amount ) ) {
/**
* If the $total_amount is empty and $order_item_id is empty then we will calculate the commission based on the product price.
* There is a case where the $total_amount is empty and $order_item_id is empty but the $product_id is not empty
* In this case, we will calculate the commission based on the product price.
* Also there is an issue when 100% coupon is applied see the below link for more details
*
* @see https://github.com/getdokan/dokan/pull/2440#issuecomment-2488159960
*/
if ( ! empty( $product_id ) && empty( $total_amount ) && empty( $order_item_id ) ) {
$product = dokan()->product->get( $product_id );

// If product price is empty the setting the price as 0
Expand Down
10 changes: 7 additions & 3 deletions includes/Product/Hooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,11 @@
<div class="dokan-store-products-filter-area dokan-clearfix">
<form class="dokan-store-products-ordeby" method="get">
<input type="text" name="product_name" class="product-name-search dokan-store-products-filter-search"
placeholder="<?php esc_attr_e( 'Enter product name', 'dokan-lite' ); ?>" autocomplete="off"

Check warning on line 191 in includes/Product/Hooks.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Found precision alignment of 3 spaces.
data-store_id="<?php echo esc_attr( $store_id ); ?>">

Check warning on line 192 in includes/Product/Hooks.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Found precision alignment of 3 spaces.
<div id="dokan-store-products-search-result" class="dokan-ajax-store-products-search-result"></div>
<input type="submit" name="search_store_products" class="search-store-products dokan-btn-theme"
value="<?php esc_attr_e( 'Search', 'dokan-lite' ); ?>">

Check warning on line 195 in includes/Product/Hooks.php

View workflow job for this annotation

GitHub Actions / Run PHPCS inspection

Found precision alignment of 3 spaces.

<?php if ( is_array( $orderby_options['catalogs'] ) && isset( $orderby_options['orderby'] ) ) : ?>
<select name="product_orderby" class="orderby orderby-search"
Expand Down Expand Up @@ -491,7 +491,7 @@

<span class="wrapper">
<input type="hidden" value="fixed" name="_per_product_admin_commission_type">
<input id="admin_commission" class="input-text wc_input_price" type="text" name="_per_product_admin_commission" value="<?php echo $admin_commission; ?>">
<input id="admin_commission" class="input-text wc_input_price" min="0" max="100" type="text" name="_per_product_admin_commission" value="<?php echo wc_format_localized_price( $admin_commission ); ?>">
<span class="additional_fee">
<?php echo esc_html( '% &nbsp;&nbsp; +' ); ?>
<input class="input-text wc_input_price" type="text" name="_per_product_admin_additional_fee" value="<?php echo wc_format_localized_price( $additional_fee ); ?>">
Expand Down Expand Up @@ -540,14 +540,18 @@
}

if ( isset( $_POST['_per_product_admin_commission'] ) ) { // phpcs:ignore
$admin_commission = ( '' === $_POST['_per_product_admin_commission'] ) ? '' : sanitize_text_field( $_POST['_per_product_admin_commission'] ); // phpcs:ignore
$_per_product_admin_commission = wc_format_decimal( sanitize_text_field( $_POST['_per_product_admin_commission'] ) ); // phpcs:ignore

if ( 0 <= $_per_product_admin_commission && 100 >= $_per_product_admin_commission ) {
$admin_commission = ( '' === $_POST['_per_product_admin_commission'] ) ? '' : $_per_product_admin_commission; // phpcs:ignore
}
}

if ( isset( $_POST['_per_product_admin_additional_fee'] ) ) { // phpcs:ignore
$additional_fee = ( '' === $_POST['_per_product_admin_additional_fee'] ) ? '' : sanitize_text_field( $_POST['_per_product_admin_additional_fee'] ); // phpcs:ignore
}

update_post_meta( $post_id, '_per_product_admin_commission', wc_format_decimal( $admin_commission ) );
update_post_meta( $post_id, '_per_product_admin_commission', $admin_commission );
update_post_meta( $post_id, '_per_product_admin_additional_fee', wc_format_decimal( $additional_fee ) );
}
}
2 changes: 0 additions & 2 deletions src/admin/components/CombineInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@ import Debounce from "debounce";
let newPercentage = this.validatePercentage( newVal.percentage );
let oldPercentage = this.validatePercentage( oldVal.percentage );

console.log(newPercentage, oldPercentage);

if ( ! newPercentage || '' === newPercentage || Number( newPercentage ) < 0 || Number( newPercentage ) > 100 ) {
newPercentage = oldPercentage;
}
Expand Down
71 changes: 54 additions & 17 deletions src/admin/components/Commission/CategoryBasedCommission.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<div class='flex flex-row'>
<div class='flex flex-row w-1/2 items-center min-h-[3rem] border-0 !border-r-[1px] !border-b-[1px] border-[#e9e9ea] border-solid pl-[5px]'>
<button type='button' class='p-1 d-xs:pl-1 md:pl-4 bg-transparent bg-co border-none cursor-pointer' @click='()=>allCategroyEnabled = !allCategroyEnabled'>
<i class="far" :class='! allCategroyEnabled ? "fa-minus-square text-black" : "fa-plus-square text-[#F05025]"'></i>
<i class="far" :class='! allCategroyEnabled ? "fa-minus-square text-black" : "fa-plus-square text-[#4C19E6]"'></i>
</button>
<p class='d-xs:text-[8px] sm:text-[14px] !m-0'>{{__( 'All Categories', 'dokan-lite' )}}</p>
</div>
Expand All @@ -32,7 +32,7 @@
id="percentage_commission"
name="percentage_commission"
ref='percentage'
:value="commission.all.percentage"
:value="formatValue( commission.all.percentage )"
v-on:input="e => handleAllCategoryInput(e.target.value, 'percentage', commission.all.percentage )"
style="border: none !important;"
/>
Expand All @@ -49,7 +49,7 @@
id="fixed_commission"
name="fixed_commission"
ref='fixed'
:value="commission.all.flat"
:value="formatValue( commission.all.flat )"
v-on:input="e => handleAllCategoryInput(e.target.value, 'flat', commission.all.flat )"
style="border: none !important;"
/>
Expand All @@ -66,7 +66,7 @@
<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'>
<span :title='item.name'>{{ item.name }}</span>
<span :title='item.name' v-html="item.name"></span>
<span class='d-xs:text-[6px] sm:text-[12px] text-gray-500' :title='__( "Category ID", "dokan" )'>#{{ item.term_id }}</span>
</p>
</div>
Expand All @@ -79,7 +79,7 @@
id="percentage_commission"
name="percentage_commission"
ref='percentage'
:value="getCommissionValue( 'percentage', item.term_id )"
:value="formatValue( getCommissionValue( 'percentage', item.term_id ) )"
v-on:input="e => commissinItemHandler( e.target.value, 'percentage', item.term_id, getCommissionValue( 'percentage', item.term_id ) )"
style="border: none !important;"
/>
Expand All @@ -96,8 +96,8 @@
id="fixed_commission"
name="fixed_commission"
ref='flat'
:value="getCommissionValue( 'flat', item.term_id )"
v-on:input="e => commissinItemHandler( e.target.value, 'flat', item.term_id, getCommissionValue( 'percentage', item.term_id ) )"
:value="formatValue( getCommissionValue( 'flat', item.term_id ) )"
v-on:input="e => commissinItemHandler( e.target.value, 'flat', item.term_id, getCommissionValue( 'flat', item.term_id ) )"
style="border: none !important;"
/>
</div>
Expand All @@ -108,6 +108,8 @@
</template>

<script>
import Debounce from "debounce";

export default {
name: 'CategoryBasedCommission',
props: {
Expand Down Expand Up @@ -159,8 +161,10 @@
this.commission.all = this.value.all;
}

if ( typeof this.value === 'object' && this.value.hasOwnProperty( 'items' ) && typeof this.value.items === 'object') {
if ( typeof this.value === 'object' && this.value.hasOwnProperty( 'items' ) && ! Array.isArray( this.value.items ) ) {
this.commission.items = this.value.items;
} else {
this.commission.items = {};
}

dokan.api.get('/products/multistep-categories').then( data => {
Expand Down Expand Up @@ -253,10 +257,13 @@
return this.commission.all[comission_type];
},

commissinItemHandler( value, commission_type, term_id, oldValue = '' ) {
if (isNaN( value )) {
value = oldValue
commissinItemHandler: Debounce( function( value, commission_type, term_id, oldValue = '' ) {
if ( 'percentage' === commission_type ) {
value = this.validatePercentage( this.unFormatValue( value ) );
} else {
value = this.unFormatValue( value );
}

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

let data = JSON.parse( JSON.stringify( this.commission.all ) );
Expand All @@ -277,17 +284,19 @@
}

this.emitComponentChange( JSON.parse( JSON.stringify( this.commission ) ) )
},
}, 700 ),

handleAllCategoryInput( value, commission_type, oldValue = '' ) {
if (isNaN( value )) {
value = oldValue
handleAllCategoryInput: Debounce( function( value, commission_type, oldValue = '' ) {
if ( 'percentage' === commission_type ) {
value = this.validatePercentage( this.unFormatValue( value ) );
} else {
value = this.unFormatValue( value );
}
this.$set( this.commission.all, commission_type, value );
this.$set(this.commission, 'items', {});

this.emitComponentChange( JSON.parse( JSON.stringify( this.commission ) ) )
},
}, 700 ),

deleteDuplicateCategories( items ) {
let self = this;
Expand Down Expand Up @@ -355,7 +364,35 @@
} );

this.$set( this.commission, 'items', children );
}
},

unFormatValue: ( value ) => {
if ( value === '' ) {
return value;
}

return String( accounting.unformat(value, dokan.currency.decimal) );
},

formatValue: ( value ) => {
if ( value === '' ) {
return value;
}

return accounting.formatNumber( value, dokan.currency.precision, dokan.currency.thousand, dokan.currency.decimal );
},

validatePercentage( percentage ) {
if ( percentage === '' ) {
return percentage;
}

if ( Number( percentage ) < 0 || Number( percentage ) > 100 ) {
percentage = '';
}

return percentage;
},
}
}
</script>
Expand Down
4 changes: 2 additions & 2 deletions src/admin/components/Fields.vue
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@
/>
</div>

<p v-if="hasError( fieldData.name )" class="dokan-error">
<p v-if="hasError( fieldData.name )" class="dokan-error pt-0 pl-5 pb-5 m-0">
{{ getError( fieldData.label ) }}
</p>
<p v-if="hasValidationError( fieldData.name )" class="dokan-error">
<p v-if="hasValidationError( fieldData.name )" class="dokan-error pl-5 pb-5">
{{ getValidationErrorMessage( fieldData.name ) }}
</p>
</div>
Expand Down
33 changes: 28 additions & 5 deletions src/admin/pages/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -433,13 +433,36 @@
if ( ! this.errors.includes( field ) ) {
this.errors.push( field );

// If flat or percentage commission is set. Remove the required field.
if ( 'flat' === value['commission_type'] || 'percentage' === value['commission_type'] ) {
if ( 'flat' === value['commission_type'] || 'percentage' === value['commission_type'] || 'combine' === value['commission_type'] || 'fixed' === value['commission_type'] ) {
this.errors = this.arrayRemove( this.errors, 'commission_category_based_values' );
}

if ( 'category_based' === value['commission_type'] ) {
this.errors = this.arrayRemove( this.errors, 'admin_percentage' );
this.errors = this.arrayRemove( this.errors, 'additional_fee' );
}
}
}

if ( field in value && 'category_based' === value['commission_type'] ) {
let alreadyAdded = ! this.errors.includes( field );

// Validate the commission_category_based_values
if (
'commission_category_based_values' in value &&
typeof value['commission_category_based_values'] === 'object' &&
value?.commission_category_based_values?.all &&
value?.commission_category_based_values?.all?.flat &&
String( value?.commission_category_based_values?.all?.flat ).length > 0 &&
value?.commission_category_based_values?.all?.percentage &&
String( value?.commission_category_based_values?.all?.percentage ).length > 0 &&
alreadyAdded
) {
this.errors = this.arrayRemove( this.errors, 'commission_category_based_values' );
} else {
this.errors.push( 'commission_category_based_values' );
}
}
} );
} );

Expand Down Expand Up @@ -1096,7 +1119,7 @@
}

.metabox-holder {
width: 40%;
width: 100%;

.settings-header {
display: block;
Expand Down Expand Up @@ -1129,7 +1152,7 @@
@media only screen and (max-width: 768px) {
.dokan-settings-wrap {
.nav-tab-wrapper {
width: 35% !important;
width: 35%;

.nav-tab {
.nav-content {
Expand All @@ -1145,7 +1168,7 @@
}

.metabox-holder {
width: 65%;
width: 100%;

.settings-header {
.settings-content {
Expand Down
17 changes: 1 addition & 16 deletions src/admin/pages/VendorSingle.vue
Original file line number Diff line number Diff line change
Expand Up @@ -574,22 +574,7 @@ export default {
}

if ( ! response.admin_commission_type ) {
this.store.admin_commission_type = 'flat';
}

if ( this.store.admin_additional_fee ) {
this.store.admin_additional_fee = accounting.formatNumber( this.store.admin_additional_fee, dokan.currency.precision, dokan.currency.thousand, dokan.currency.decimal, dokan.currency.format );
}

/**
* if admin commission type is flat and no admin commission is set then it will not not set
*
* if admin commission type is flat and admin commission is set to 0 then it will show 0
*
* blank string is for not set
*/
if (this.store.admin_commission_type === 'flat' && this.store.admin_commission !== '') {
this.store.admin_commission = accounting.formatNumber( this.store.admin_commission, dokan.currency.precision, dokan.currency.thousand, dokan.currency.decimal, dokan.currency.format );
this.store.admin_commission_type = '';
}
},

Expand Down
Loading