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 several commission issues #2502

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from

Conversation

Aunshon
Copy link
Collaborator

@Aunshon Aunshon commented Jan 6, 2025

All Submissions:

  • My code follow the WordPress' coding standards
  • My code satisfies feature requirements
  • My code is tested
  • My code passes the PHPCS tests
  • My code has proper inline documentation
  • I've included related pull request(s) (optional)
  • I've included developer documentation (optional)
  • I've added proper labels to this pull request

Changes proposed in this Pull Request:

Fixed some bugs of commissions as mentioned in the issue.

Related Pull Request(s)

Closes

How to test the changes in this Pull Request:

  • Test as mentioned in the issues.
  • Test all commission experiences global, vendor, product, subscription product, auction product, setup wizard.
  • Test the earning calculation and commission again.

Changelog entry

- **fix:** Fix earning suggestion in vendor dashboard when product edit page loads initially. 
- **fix:** Fix vendor earning suggestion currency, currency position, decimal separator in vendor dashboard product edit page.
- **fix:** Fix vendor earning suggestion for invalid product price.

…roduct edit page the earning suggestion shows the wrong value.
…fferent decimal and thousand separator, on change of price the earning suggestion updates to wrong decimal and thousand separator.
… suggestion should display zero, but it still shows the previous value.

Fixed: When using a decimal comma separator, the decimal value doesn’t work for simple products, and variable products display as zero. (both regular price & discounted price)
Fixed: Fatal Error on negative value for regular price: If a negative value is given for price (both simple and variable), there is a fatal error.
@Aunshon Aunshon self-assigned this Jan 6, 2025
Copy link
Contributor

coderabbitai bot commented Jan 6, 2025

Walkthrough

This pull request introduces comprehensive improvements across multiple files in the Dokan plugin, focusing on product pricing, commission calculations, and code quality. The changes span JavaScript and PHP files, enhancing functionality in the product editor, commission handling, and product category management. Key modifications include adding new methods for money formatting, improving type handling, fixing method naming, and updating test coverage for various product and commission scenarios.

Changes

File Change Summary
assets/src/js/product-editor.js Added formatMoney and unormatMoney methods to handle monetary value formatting, updated price assignment logic
includes/Commission.php Updated get_commission method with new parameter, fixed method name typos, marked calculate_commission as deprecated
includes/ProductCategory/Helper.php Added get_product_terms method, improved type handling for product-related methods
includes/REST/CommissionControllerV1.php Modified get_commission method call with additional parameters
templates/products/edit-product-single.php Updated earning amount display with improved HTML structure
tests/php/src/Commission/CommissionTest.php Added variable product settings data provider, new test methods for commission calculations
assets/src/js/setup-wizard/commission/AdminCommission.vue Simplified handling of default values for fixed and percentage properties
src/admin/components/CombineInput.vue Streamlined input handling for percentage and fixed inputs, added validation for negative values

Assessment against linked issues

Objective Addressed Explanation
Initial Earning Suggestion Wrong (#4049)
Decimal and thousand separator wrong (#4049)
Fatal Error on negative value for regular price (#4049)
Currency sign position does not match (#4049) Changes do not address currency sign positioning.
Decimal comma separator issue (#4049)
Price removal should display zero (#4049)

Possibly related PRs

Suggested labels

QA approved, Test Automation, Needs: Testing

Suggested reviewers

  • mrabbani

Poem

🐰 Hopping through code with glee,
Pricing logic now set free!
Commissions dance, categories sing,
Our plugin's got a brand new swing!
Rabbit's code review is done with cheer! 🎉


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (8)
includes/ProductCategory/Helper.php (2)

68-68: Improve error handling for empty product terms
Retrieving terms through get_product_terms centralizes logic, but consider logging or gracefully handling cases when terms unexpectedly return empty to improve debugging.


309-327: Centralize product term retrieval
The new get_product_terms method consolidates term retrieval. This is beneficial for maintainability. However, ensure that no legacy code duplicates the retrieval approach.

includes/Commission.php (2)

593-596: Clarify decimal separator comment
The note about decimal comma usage is helpful. Consider adding a test scenario for it or referencing a known issue or solution to help maintainers quickly identify the context.

🧰 Tools
🪛 GitHub Actions: Inspections

[error] Variable "$orderItemId" is not in valid snake_case format, should be "$order_item_id"


602-602: Guard against empty product object
When retrieving $product, ensure $product is valid before calling $product->get_price(). This is partially handled, but a more explicit check and potential warning could help.

🧰 Tools
🪛 GitHub Actions: Inspections

[error] Variable "$orderItemId" is not in valid snake_case format, should be "$order_item_id"

assets/src/js/product-editor.js (4)

962-962: Safeguard against undefined or non-numeric values.
When passing priceAmount into the AJAX request, consider parsing or validating it to ensure you’re not sending unexpected strings.


988-990: Typographical nitpick.
The method name is spelled unormatMoney; consider renaming it to unformatMoney for clarity.


995-997: Use descriptive variable names.
vandorPrice is likely meant to be vendorPrice. Renaming helps avoid confusion in the future.


1000-1000: Potentially refine negative price handling.
Blocking form submission if the vendor price is negative may be appropriate, but confirm whether partial refunds or other scenarios could yield negative amounts in legitimate cases.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8bc25cf and ea68037.

📒 Files selected for processing (6)
  • assets/src/js/product-editor.js (3 hunks)
  • includes/Commission.php (3 hunks)
  • includes/ProductCategory/Helper.php (4 hunks)
  • includes/REST/CommissionControllerV1.php (1 hunks)
  • templates/products/edit-product-single.php (1 hunks)
  • tests/php/src/Commission/CommissionTest.php (24 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
assets/src/js/product-editor.js

[error] 968-968: isNaN is unsafe. It attempts a type coercion. Use Number.isNaN instead.

See the MDN documentation for more details.
Unsafe fix: Use Number.isNaN instead.

(lint/suspicious/noGlobalIsNan)

🪛 GitHub Actions: Inspections
includes/Commission.php

[error] Variable "$orderItemId" is not in valid snake_case format, should be "$order_item_id"

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: e2e_api tests
🔇 Additional comments (35)
includes/REST/CommissionControllerV1.php (1)

136-138: Confirm usage of new boolean parameters
Two additional boolean parameters (false, false) are being passed to dokan()->commission->get_commission. Ensure these align with the new logic in Commission and handle default operations as intended.

Would you like me to generate a quick script to search for calls to get_commission across the codebase to confirm consistent usage of these new parameters?

includes/ProductCategory/Helper.php (3)

5-5: Confirm WC_Product import usage
The import of WC_Product is a good addition. Validate that no naming conflicts exist and that the class references remain consistent throughout the file.


262-287: Validate the new product type checks
When $product is not an instance of WC_Product, the code attempts wc_get_product. Confirm that this logic covers all product scenarios, including edge cases like deleted or non-purchasable items.


301-301: No direct issues
Line 301 is introducing usage of get_product_terms; looks good and consistent with the new approach.

includes/Commission.php (3)

177-177: Type consistency improved with floatval
Switching from (float) to floatval() is fine. Verify no downstream float-cast behavior changes.

🧰 Tools
🪛 GitHub Actions: Inspections

[error] Variable "$orderItemId" is not in valid snake_case format, should be "$order_item_id"


565-570: Ensure backward compatibility of new parameter
The addition of $override_total_amount_by_product_price in get_commission extends functionality. Confirm that legacy calls still work correctly when the third parameter is not passed.

🧰 Tools
🪛 GitHub Actions: Inspections

[error] Variable "$orderItemId" is not in valid snake_case format, should be "$order_item_id"


598-598: Override total amount check
$override_total_amount_by_product_price logic ensures a fallback to product price. Double-check for scenarios where $product->get_price() might be zero or missing due to discount edge cases.

🧰 Tools
🪛 GitHub Actions: Inspections

[error] Variable "$orderItemId" is not in valid snake_case format, should be "$order_item_id"

templates/products/edit-product-single.php (1)

295-295: Enhance user message for vendor earnings
The inline string “You Earn” is now complemented by a properly formatted price display. This is a good approach. Optionally, consider localizing more robustly, ensuring all currency formatting is consistent sitewide.

assets/src/js/product-editor.js (4)

952-953: Consider validating the price input before assigning.
Currently, priceAmount is set to either sale_price or product_price, which may be uninitialized or non-numeric. Adding an explicit check or parse step, in addition to the default of 0, can provide more clarity and avoid unintended values.


978-986: Ensure consistent decimal precision across your application.
formatMoney specifies a precision of 4. Verify that this aligns with the rest of your pricing logic and currency settings elsewhere in the code.


998-999: Validate unformatted vendor price.
Before or after unformatting the vendor price, consider verifying numeric correctness.


969-969: ⚠️ Potential issue

Avoid using the global isNaN for type checks.
According to static analysis, isNaN performs type coercions that can lead to unexpected results. Use Number.isNaN with a numeric cast instead.

Below is an example fix:

-if ( ! isNaN( response ) ) {
+if ( ! Number.isNaN( Number( response ) ) ) {
    earning_suggestion.html( Dokan_Editor.formatMoney( response ) );
}

Likely invalid or redundant comment.

tests/php/src/Commission/CommissionTest.php (23)

116-132: Global commission configuration looks good.
No issues found in this logic; the fixed commission scenario is handled properly for smaller amounts.


Line range hint 199-230: Global settings updates appear consistent.
This chunk correctly sets single-quoted keys in $commission_global_options.


Line range hint 258-292: Category-based logic is consistent.
No issues here; code is cohesive and aligns with the test scenario.


314-332: Improved reliability for global strategy.
Implementation is consistent with the test plan described in the docblock.


354-362: Flat commission approach validated.
Code is straightforward and tested thoroughly for the flat-based setting.


383-392: Percentage fallback correctly configured.
Logic remains consistent with preceding test scenarios; no concerns.


416-425: Commission with vendor-specific percentage looks good.
The data set is tested accurately.


449-458: Combine commission approach.
No anomalies found in these global settings for the combine scenario.


482-491: Robust coverage of product-level combination commissions.
All references to array keys align with the single-quoted style.


515-524: Zero-price scenario gracefully handled.
Confirmed that the code properly covers edge cases for $0 amounts.


544-561: Commission distribution verified.
Handling of category_4 is in line with the existing logic.


584-601: Category-based commissions applied consistently.
These lines appropriately handle the same scenario with zero total price.


611-618: Properly reintegrates item-based settings.
No issues discovered with reassigning category IDs.


640-657: Category refinement is correct.
No concerns with the logic or formatting.


680-697: Ensures fallback to zero commission on null totals.
The code block is consistent with the overall approach.


707-714: Vendor-based category notices handled.
All changes appear correct and consistent with earlier patterns.


736-753: Global fee logic remains uniform.
The coverage for $settings['global_setting'] is adequate.


763-770: Flat commission coverage extended.
No further issues detected.


792-809: Percentage commission coverage extended.
Implementation parallels existing tests.


819-826: Confirmed zero-value percentage logic.
No issues uncovered in this segment.


1041-1063: Commission settings storage looks correct.
The calls to $product_setting->save, $vendor_setting->save, and $global_setting->save accurately reflect the data arrays.


1136-1202: Data provider for variable products.
This new data provider method elegantly supplies consistent test parameters.


1204-1274: Variable product commission test.
Testing multiple variations under a single product covers more edge cases, improving reliability.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
src/admin/components/CombineInput.vue (1)

100-101: Define formatPositiveValue as a standard function instead of an arrow function

Defining methods as arrow functions can cause issues with this binding in Vue components. It's recommended to use standard function definitions within the methods object to ensure proper context.

Apply this diff to redefine the method:

-                formatPositiveValue: ( value ) => {
+                formatPositiveValue( value ) {
assets/src/js/setup-wizard/commission/AdminCommission.vue (1)

79-85: Improve commission value validation and type handling.

While converting empty strings to 0 is reasonable, the method could benefit from more robust value validation.

Consider this enhanced implementation:

             fixedCOmmissionhandler(data) {
-                if (data.fixed === '') {
-                    data.fixed =  0;
-                }
-                if (data.percentage === '') {
-                    data.percentage = 0;
-                }
+                // Convert to numbers and ensure non-negative values
+                data.fixed = data.fixed === '' ? 0 : Math.max(0, Number(data.fixed));
+                data.percentage = data.percentage === '' ? 0 : Math.max(0, Math.min(100, Number(data.percentage)));

                 this.fixedCommission = data;
             },

This ensures:

  • Explicit type conversion using Number()
  • Non-negative commission values
  • Percentage values between 0 and 100
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ea68037 and 867f807.

📒 Files selected for processing (2)
  • assets/src/js/setup-wizard/commission/AdminCommission.vue (1 hunks)
  • src/admin/components/CombineInput.vue (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: e2e_api tests
🔇 Additional comments (3)
src/admin/components/CombineInput.vue (2)

12-13: Ensure proper synchronization after replacing v-model with :value and v-on:input

Replacing v-model with :value and v-on:input changes the way data is synchronized between the input and the component's state. Ensure that the onInput method correctly emits updated values and that any two-way binding or reactivity is preserved.


34-35: Verify data binding consistency for fixed input

Similar to the percentage input, confirm that replacing v-model with :value and v-on:input maintains proper synchronization of the fixed value. Ensure that user input updates the component's state and is emitted correctly.

assets/src/js/setup-wizard/commission/AdminCommission.vue (1)

79-85: Verify commission calculations with product editor integration.

Given the PR's focus on fixing commission issues and its relation to product pricing changes, ensure comprehensive testing of commission calculations.

Please verify:

  1. Integration with the new money formatting methods in product editor
  2. Correct handling of commission calculations for both fixed and percentage types
  3. Edge cases with minimum/maximum commission values
✅ Verification successful

✓ Commission value handling is well-tested and follows established patterns

The code change follows the same pattern used throughout the codebase for handling empty commission values, with comprehensive test coverage across unit, integration, and API tests.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for related test files and commission calculation logic
rg -l "commission|pricing" "tests/"

# Look for money formatting usage
ast-grep --pattern 'formatMoney($_)'

Length of output: 1432


Script:

#!/bin/bash
# Search for AdminCommission related tests
rg -l "AdminCommission" "tests/"

# Look for test cases handling empty/zero commission values
rg "commission.*0|commission.*empty" "tests/" -A 5

# Search for Vue component test files
fd -e spec.js -e spec.ts -e test.js -e test.ts

Length of output: 70249

Comment on lines +80 to +86
validateNegative( value ) {
if ( Number( value ) < 0 ) {
value = '';
}

return value;
},
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

Handle non-numeric and NaN values in validateNegative method

The validateNegative method uses Number(value), which can return NaN for invalid inputs. Comparing NaN with numbers results in false, so the condition Number(value) < 0 won't catch NaN values. This could lead to unexpected behavior.

Apply this diff to handle NaN values explicitly:

                 validateNegative( value ) {
+                    let num = Number( value );
+                    if ( isNaN( num ) || num < 0 ) {
+                        value = '';
+                    } else {
+                        value = num;
+                    }
                     return value;
                 },
📝 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
validateNegative( value ) {
if ( Number( value ) < 0 ) {
value = '';
}
return value;
},
validateNegative( value ) {
let num = Number( value );
if ( isNaN( num ) || num < 0 ) {
value = '';
} else {
value = num;
}
return value;
},

Comment on lines +88 to +94
onInput: Debounce( function( currentValue, type ) {
let self = this;
let data = {
fixed: self.fixed ? accounting.unformat(self.fixed, dokan.currency.decimal) : '',
percentage: self.percentage ? accounting.unformat(self.percentage, dokan.currency.decimal): ''
};
let data = JSON.parse( JSON.stringify( { ...self.value }) );
data[ type ] = '' !== currentValue ? String( currentValue ) : '';

data.fixed = '' !== data.fixed ? self.validateNegative( accounting.unformat( data.fixed, dokan.currency.decimal ) ) : '';
data.percentage = '' !== data.percentage ? self.validateNegative( self.validatePercentage( accounting.unformat( data.percentage, dokan.currency.decimal ) ) ) : '';
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid using JSON.parse(JSON.stringify(...)) for cloning objects

Using JSON.parse(JSON.stringify(...)) to clone objects can lead to issues with properties that cannot be serialized (like functions) and can be inefficient. It's better to use a more appropriate cloning method.

Apply this diff to simplify the cloning process:

-                    let data = JSON.parse( JSON.stringify( { ...self.value } ) );
+                    let data = { ...self.value };

If a deep clone is necessary, consider using a utility like lodash.cloneDeep or a similar function.

📝 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
onInput: Debounce( function( currentValue, type ) {
let self = this;
let data = {
fixed: self.fixed ? accounting.unformat(self.fixed, dokan.currency.decimal) : '',
percentage: self.percentage ? accounting.unformat(self.percentage, dokan.currency.decimal): ''
};
let data = JSON.parse( JSON.stringify( { ...self.value }) );
data[ type ] = '' !== currentValue ? String( currentValue ) : '';
data.fixed = '' !== data.fixed ? self.validateNegative( accounting.unformat( data.fixed, dokan.currency.decimal ) ) : '';
data.percentage = '' !== data.percentage ? self.validateNegative( self.validatePercentage( accounting.unformat( data.percentage, dokan.currency.decimal ) ) ) : '';
onInput: Debounce( function( currentValue, type ) {
let self = this;
let data = { ...self.value };
data[ type ] = '' !== currentValue ? String( currentValue ) : '';
data.fixed = '' !== data.fixed ? self.validateNegative( accounting.unformat( data.fixed, dokan.currency.decimal ) ) : '';
data.percentage = '' !== data.percentage ? self.validateNegative( self.validatePercentage( accounting.unformat( data.percentage, dokan.currency.decimal ) ) ) : '';

Comment on lines +79 to 85
data.fixed = 0;
}
if (data.percentage === '') {
data.percentage = this.fixedCommission.percentage ?? 0;
data.percentage = 0;
}

this.fixedCommission = data;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fix method naming convention.

The method name fixedCOmmissionhandler has inconsistent capitalization. Following Vue.js naming conventions, method names should use camelCase.

Rename the method to fixedCommissionHandler:

-            fixedCOmmissionhandler(data) {
+            fixedCommissionHandler(data) {

Don't forget to update the template where this method is referenced:

-                v-on:change="fixedCOmmissionhandler"
+                v-on:change="fixedCommissionHandler"

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

@Aunshon Aunshon added Needs: Testing This requires further testing Needs: Dev Review It requires a developer review and approval labels Jan 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs: Dev Review It requires a developer review and approval Needs: Testing This requires further testing
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant