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

sync from polaris datas to erxes #5041

Merged
merged 10 commits into from Mar 11, 2024
Merged

sync from polaris datas to erxes #5041

merged 10 commits into from Mar 11, 2024

Conversation

Mygmarsuren
Copy link
Collaborator

ISSUE

Context

Your context here. Additionally, any screenshots. Delete this line.

// Delete the below section once completed

PR Checklist

  • Description is clearly stated under Context section
  • Screenshots and the additional verifications are attached

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

PR Type: Enhancement

PR Summary: This pull request introduces several enhancements aimed at synchronizing data from Polaris to Erxes. It adds new utility functions for fetching and updating customer, loan, and saving contract data. Additionally, it extends the UI components to include new functionalities such as checking and syncing customers, loans, and savings accounts directly from the UI. The changes span across multiple files, including utility functions for API calls, GraphQL schema updates for new mutations, and UI updates for handling the new functionalities.

Decision: Comment

📝 Type: 'Enhancement' - not supported yet.
  • Sourcery currently only approves 'Typo fix' PRs.
✅ Issue addressed: this change correctly addresses the issue or implements the desired feature.
No details provided.
📝 Complexity: the changes are too large or complex for Sourcery to approve.
  • Files deleted: Sourcery does not currently approve diffs with deleted files.
  • Big diff: the diff is too large to approve with confidence.

General suggestions:

  • Consider abstracting common logic in utility functions to reduce code duplication and improve maintainability.
  • Ensure that newly introduced state management and asynchronous operations in UI components are well-documented and tested to maintain code quality.
  • Review the necessity of direct state updates from props in UI components to avoid potential redundancy and ensure optimal performance.
  • Evaluate the complexity introduced by new GraphQL mutations and consider abstracting similar functionalities to simplify the schema and improve maintainability.
  • Given the significant changes, especially in data processing and UI interactions, ensure comprehensive testing, including unit, integration, and end-to-end tests, to maintain reliability and user experience.

Thanks for using Sourcery. We offer it for free for open source projects and would be very grateful if you could help us grow. If you like it, would you consider sharing Sourcery on your favourite social media? ✨

Share Sourcery

Help me be more useful! Please click 👍 or 👎 on each comment to tell me if it was helpful.

Comment on lines 43 to 46
const onClickCheck = (e) => {
toCheckCustomers();
this.setState({ items: items });
};
Copy link

Choose a reason for hiding this comment

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

question (llm): The onClickCheck function directly modifies the component's state using this.setState({ items: items }), which might not be necessary since items is already part of the component's props. Ensure that this state update is required for the component's functionality, or consider using props directly if the state update is redundant.

Comment on lines 33 to 35
const responseData = await getSavingDetail(subdomain, {
number: preSavingContract.number,
});
Copy link

Choose a reason for hiding this comment

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

suggestion (llm): Consider handling the scenario where getSavingDetail might return an error or null response. This could happen due to network issues or if the saving detail for the provided number does not exist. Currently, the code assumes a successful response with data.

@@ -30,6 +30,18 @@ export const initBroker = async () => {
},
);

consumeRPCQueue(
Copy link

Choose a reason for hiding this comment

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

issue (llm): The addition of separate queue consumers for specific operations (loans:contracts.updateOne and loans:contractType.find) introduces a higher level of complexity and redundancy, particularly with the inclusion of verbose logging that might not be necessary (console.log('selector:', selector, modifier);). This approach increases the cognitive load for developers who need to understand and maintain multiple consumers, potentially leading to confusion and maintenance challenges.

A more streamlined approach could involve consolidating these operations into a more generic queue consumer that handles various types of updates. This would not only reduce the number of consumers but also make the system more flexible and easier to maintain. For example, a single consumer that takes in a query and an update object could handle different update operations without the need for separate consumers for each specific case.

Here's a suggested refactor that encapsulates the update functionality in a more generic manner:

consumeRPCQueue('loans:contract.update', async ({ subdomain, data }) => {
  const models = await generateModels(subdomain);
  const { query, update } = data; // Assuming data contains query and update objects

  // Perform the update operation based on the provided query and update data
  const result = await models.Contracts.updateOne(query, update);

  return {
    status: 'success',
    data: result,
  };
});

This approach minimizes the complexity and redundancy in the codebase, making it more maintainable and easier to extend in the future.

@@ -60,6 +60,17 @@ export const initBroker = async () => {
},
);

consumeRPCQueue(
Copy link

Choose a reason for hiding this comment

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

issue (llm): The addition of a new consumeRPCQueue call for 'savings:contracts.updateOne' alongside the existing pattern for handling RPC queue messages introduces a notable increase in code complexity. This is primarily due to the increased code length, duplication of logic, and the added cognitive load required to understand and maintain these separate yet similar operations.

To mitigate these issues, consider abstracting the common logic into a more generic function or handler. This approach can significantly reduce duplication and simplify understanding the overall flow of RPC message handling. For instance, creating a function that handles the update operation based on parameters can consolidate the logic into a single, more manageable place. This not only makes the codebase cleaner but also eases future modifications and maintenance.

Here's a suggested refactor that encapsulates the common logic into a single function, thereby reducing complexity and improving code maintainability:

async function handleRPCUpdate(modelName, subdomain, data, isCustomUpdate = false) {
  const models = await generateModels(subdomain);
  let updateResult;
  if (isCustomUpdate) {
    // Handle custom update logic
    updateResult = await models[modelName].updateOne(data.selector, data.modifier);
  } else {
    // Handle direct update logic
    updateResult = await models[modelName].updateOne(
      { _id: data._id },
      { $set: { number: data.number } }
    );
  }
  return {
    status: 'success',
    data: updateResult,
  };
}

// Usage for RPC queue message handling
consumeRPCQueue('savings:contracts.updateOne', async ({ subdomain, data }) => {
  return handleRPCUpdate('Contracts', subdomain, data, true);
});

This refactor not only reduces the code complexity but also enhances the scalability of handling future RPC queue messages by providing a unified method to manage updates.

Comment on lines 4 to 10
const savingDetail = await fetchPolaris({
subdomain,
op: '13610100',
data: [params.number, 0],
}).then((response) => JSON.parse(response));

return savingDetail;
Copy link

Choose a reason for hiding this comment

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

suggestion (rule): Sourcery has identified the following issue:

Suggested change
const savingDetail = await fetchPolaris({
subdomain,
op: '13610100',
data: [params.number, 0],
}).then((response) => JSON.parse(response));
return savingDetail;
return await fetchPolaris({
subdomain,
op: '13610100',
data: [params.number, 0],
}).then((response) => JSON.parse(response));


ExplanationSomething that we often see in people's code is assigning to a result variable
and then immediately returning it.

Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.

Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.

Comment on lines 47 to 56
if (dateNames.includes(key)) {
const polarisDate = new Date(
new Date(polarisData[key]).getTime() -
new Date(polarisData[key]).getTimezoneOffset() * 60000,
);
const mainDate = new Date(String(value));
if (polarisDate.getTime() !== mainDate.getTime()) {
return mainData;
}
} else return mainData;
Copy link

Choose a reason for hiding this comment

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

suggestion (rule): Sourcery has identified the following issue:

  • Use block braces for ifs, whiles, etc. (use-braces)
Suggested change
if (dateNames.includes(key)) {
const polarisDate = new Date(
new Date(polarisData[key]).getTime() -
new Date(polarisData[key]).getTimezoneOffset() * 60000,
);
const mainDate = new Date(String(value));
if (polarisDate.getTime() !== mainDate.getTime()) {
return mainData;
}
} else return mainData;
if (dateNames.includes(key)) {
const polarisDate = new Date(
new Date(polarisData[key]).getTime() -
new Date(polarisData[key]).getTimezoneOffset() * 60000,
);
const mainDate = new Date(String(value));
if (polarisDate.getTime() !== mainDate.getTime()) {
return mainData;
}
} else {
return mainData;
}


ExplanationIt is recommended to always use braces and create explicit statement blocks.

Using the allowed syntax to just write a single statement can lead to very confusing
situations, especially where subsequently a developer might add another statement
while forgetting to add the braces (meaning that this wouldn't be included in the condition).

Comment on lines 74 to 75
if (polarisDate.getTime() !== mainDate.getTime())
updateData[key] = polarisDate;
Copy link

Choose a reason for hiding this comment

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

suggestion (rule): Sourcery has identified the following issue:

  • Use block braces for ifs, whiles, etc. (use-braces)
Suggested change
if (polarisDate.getTime() !== mainDate.getTime())
updateData[key] = polarisDate;
if (polarisDate.getTime() !== mainDate.getTime()) {
updateData[key] = polarisDate;
}


ExplanationIt is recommended to always use braces and create explicit statement blocks.

Using the allowed syntax to just write a single statement can lead to very confusing
situations, especially where subsequently a developer might add another statement
while forgetting to add the braces (meaning that this wouldn't be included in the condition).

Comment on lines 76 to 86
} else if (fields.find((c) => c.code === key)) {
const field = fields.find((c) => c.code === key);
const index = customFieldsData.findIndex((c) => c.field === field._id);
index >= 0
? (customFieldsData[index].value = polarisData[key])
: customFieldsData.push({
field: field._id,
value: polarisData[key],
});
updateData['customFieldsData'] = customFieldsData;
} else updateData[key] = polarisData[key];
Copy link

Choose a reason for hiding this comment

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

suggestion (rule): Sourcery has identified the following issue:

  • Use block braces for ifs, whiles, etc. (use-braces)
Suggested change
} else if (fields.find((c) => c.code === key)) {
const field = fields.find((c) => c.code === key);
const index = customFieldsData.findIndex((c) => c.field === field._id);
index >= 0
? (customFieldsData[index].value = polarisData[key])
: customFieldsData.push({
field: field._id,
value: polarisData[key],
});
updateData['customFieldsData'] = customFieldsData;
} else updateData[key] = polarisData[key];
} else if (fields.find((c) => c.code === key)) {
const field = fields.find((c) => c.code === key);
const index = customFieldsData.findIndex((c) => c.field === field._id);
index >= 0
? (customFieldsData[index].value = polarisData[key])
: customFieldsData.push({
field: field._id,
value: polarisData[key],
});
updateData['customFieldsData'] = customFieldsData;
} else {
updateData[key] = polarisData[key];
}


ExplanationIt is recommended to always use braces and create explicit statement blocks.

Using the allowed syntax to just write a single statement can lead to very confusing
situations, especially where subsequently a developer might add another statement
while forgetting to add the braces (meaning that this wouldn't be included in the condition).

Comment on lines +274 to +292
const fields = await sendCommonMessage({
subdomain,
serviceName: 'forms',
action: 'fields.find',
data: {
query: {
contentType: customFieldType,
code: { $exists: true, $ne: '' },
},
projection: {
groupId: 1,
code: 1,
_id: 1,
},
},
isRPC: true,
defaultValue: [],
});
return fields;
Copy link

Choose a reason for hiding this comment

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

suggestion (rule): Sourcery has identified the following issue:

Suggested change
const fields = await sendCommonMessage({
subdomain,
serviceName: 'forms',
action: 'fields.find',
data: {
query: {
contentType: customFieldType,
code: { $exists: true, $ne: '' },
},
projection: {
groupId: 1,
code: 1,
_id: 1,
},
},
isRPC: true,
defaultValue: [],
});
return fields;
return await sendCommonMessage({
subdomain,
serviceName: 'forms',
action: 'fields.find',
data: {
query: {
contentType: customFieldType,
code: { $exists: true, $ne: '' },
},
projection: {
groupId: 1,
code: 1,
_id: 1,
},
},
isRPC: true,
defaultValue: [],
});


ExplanationSomething that we often see in people's code is assigning to a result variable
and then immediately returning it.

Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.

Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.

Copy link

sonarcloud bot commented Mar 7, 2024

Quality Gate Passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.4% Duplication on New Code

See analysis details on SonarCloud

@munkhsaikhan munkhsaikhan merged commit 9f894c1 into dev Mar 11, 2024
7 of 8 checks passed
@munkhsaikhan munkhsaikhan deleted the CheckCustomerPolaris branch March 11, 2024 09:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants