Skip to content

Feat/authorize net payment opaque data #847

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

Conversation

landonshumway-ia
Copy link
Collaborator

@landonshumway-ia landonshumway-ia commented Jun 5, 2025

Previously, our initial design for processing payment information when purchasing privileges involved sending card data directly to the backend, which was then used to call Authorize.net to make a transaction. In order to improve the security of the system, we are updating the front end to send the payment card information to Authorize.net directly using their Accept UI solution, and then sending the payment nonce token to the backend instead. This updates the backend to support that pattern.

As part of supporting this, the frontend will now need the api login id and the public client key to generate the payment collection form. This updates the system so that when a compact admin uploads their payment processing creds into the system, the public key is stored in the compact configuration object, which will then be accessible by the frontend when practitioners go to purchase privileges.

Closes #794
Closes #793

Summary by CodeRabbit

  • New Features

    • Added support for uploading and validating payment processor credentials, including public fields for secure payment collection.
    • Payment privilege purchasing now uses secure opaque payment tokens instead of raw card details.
    • Compact privilege options and purchase APIs now include public payment processor fields and sandbox status.
    • Introduced a new Vue component integrating Authorize.net AcceptUI for payment input.
  • Improvements

    • Enhanced Content Security Policy to allow necessary Authorize.Net domains for payment processing.
    • Updated API schemas and documentation to reflect new opaque payment data structure and public credential fields.
    • Anchored transaction history processing to scheduled invocation time for replayability.
    • Refactored payment UI and form handling to use opaque payment data and simplify input management.
    • Improved UI behavior by auto-scrolling to action buttons after mock data population.
    • Updated infrastructure to grant Lambda permissions and environment variables for payment processor features.
  • Bug Fixes

    • Ensured idempotent transaction storage to prevent duplicate records during transaction processing.
  • Tests

    • Added and updated tests for payment processor credential uploads, privilege purchasing with opaque data, and transaction history idempotency.
    • Expanded smoke and load tests to use secure payment tokens and validate new credential flows.
    • Enhanced unit tests with AWS mocking and coverage for credential validation errors.
  • Chores

    • Updated environment configuration and test resources to support new payment processor integration and secure data handling.
    • Cleaned up styling and localization keys related to payment inputs.

Copy link
Contributor

coderabbitai bot commented Jun 5, 2025

Walkthrough

This update refactors the payment processing flow for Authorize.Net to use opaque payment tokens instead of directly handling raw credit card data in the backend. It introduces new schema fields, updates API models, modifies test infrastructure, and ensures compliance by removing direct credit card data handling throughout the backend and test suites.

Changes

File(s) Change Summary
cloudfront-csp/index.js, CSP test snapshots, test helpers Added Authorize.Net domains to CSP headers and updated related test snapshots and helpers.
compact_configuration_client.py, purchase_client.py, privileges.py, transaction_history.py Updated backend logic to support opaque payment tokens, public credential storage, and new fields for payment processor configuration.
schema/compact/common.py, schema/compact/api.py, schema/compact/record.py Introduced new schema classes and fields for payment processor public fields and processor type.
api_stack/v1_api/api_model.py, PURCHASE_PRIVILEGE_REQUEST_SCHEMA.json Changed API model and schema to require opaque payment data instead of raw card/billing details.
api_stack/v1_api/api.py, credentials.py Updated stack and credentials logic to pass persistent stack and environment variables for payment configuration.
transaction_history_processing_workflow.py, test_transaction_monitoring.py Adjusted Step Function initial state to handle scheduled time and updated related tests.
purchases/tests/function/test_handlers/test_privilege_options.py, test_purchase_privileges.py, test_transaction_history.py, test_purchase_client.py Refactored tests to use opaque payment data, added DynamoDB mocking, and improved credential validation coverage.
smoke/compact_configuration_smoke_tests.py, smoke/purchasing_privileges_smoke_tests.py, smoke/smoke_common.py, smoke/config.py, smoke/load_test_privilege_purchasing.py, smoke/smoke_tests_env_example.json Updated smoke and load tests to use opaque payment tokens, added credential upload and validation, and introduced new config/environment variables.
compact-configuration-response.json Deleted obsolete test resource with raw card data.
webroot/src/components/PrivilegePurchaseAcceptUI/* Added new Vue component integrating Authorize.Net AcceptUI for payment tokenization.
webroot/src/components/PrivilegePurchaseFinalize/* Refactored to remove direct card input fields and integrate AcceptUI component with opaque data handling.
webroot/src/models/CompactFeeConfig/*, LicenseeUser.model.* Added support for payment SDK config fields and updated serializers to handle opaque payment data.
webroot/src/locales/* Updated locale strings to remove card-specific labels and add general payment messages.
webroot/src/network/mocks/mock.data.ts Added mock payment processor public fields and sandbox flag to mock data.
webroot/src/styles.common/mixins/purchase-flow-buttons.less Added CSS rules for button sizing inside form navigation.
Various Vue components (PrivilegePurchaseLicense, PrivilegePurchaseSelect, PrivilegePurchaseInformationConfirmation, PrivilegePurchaseAttestation) Added scroll-to-button-row behavior after mock population and added id="button-row" to button containers.

Sequence Diagram(s)

sequenceDiagram
    participant Frontend
    participant AuthorizeNet
    participant Backend
    participant DynamoDB

    Frontend->>AuthorizeNet: Send card data via Accept UI
    AuthorizeNet-->>Frontend: Return opaque payment token (opaqueData)
    Frontend->>Backend: Submit purchase request with opaqueData
    Backend->>DynamoDB: Retrieve compact configuration & public keys
    Backend->>AuthorizeNet: Process payment using opaqueData
    AuthorizeNet-->>Backend: Return payment result
    Backend-->>Frontend: Respond with transaction outcome
Loading

Assessment against linked issues

Objective Addressed Explanation
Update backend to avoid handling raw credit card data and use Authorize.Net payment tokens (#794)
Update API models and schemas to accept opaque payment data instead of card/billing fields (#794)
Store and expose public payment processor fields for frontend integration (#794)
Update tests and smoke tests to use opaque payment tokens and validate new flow (#794)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Deletion of compact-configuration-response.json (backend/compact-connect/lambdas/python/common/tests/resources/api/compact-configuration-response.json) This is a test resource removal related to compact configuration, not directly required for the Authorize.Net compliance update. However, it may be a cleanup due to schema changes.
Addition of isSandbox flag in privilege options and related schema (multiple files) The isSandbox flag is not explicitly required by the linked issue, but it may be helpful for testing and environment awareness. Its necessity is unclear from the linked objectives.

Suggested reviewers

  • jsandoval81
  • jlkravitz
  • isabeleliassen

Poem

A rabbit hops with PCI pride,
No credit cards in backend hide!
Opaque tokens now the key,
For payments safe as safe can be.
Authorize.Net, we now comply—
With tests and docs all standing by.
🐇✨ Secure, compliant, hopping high!

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ 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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @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.

@landonshumway-ia landonshumway-ia force-pushed the feat/authorize-net-payment-opaque-data branch from 6a02498 to d866bfb Compare June 6, 2025 15:13
@landonshumway-ia landonshumway-ia marked this pull request as ready for review June 6, 2025 15:22
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: 5

🧹 Nitpick comments (3)
backend/compact-connect/lambdas/python/purchases/handlers/privileges.py (1)

90-92: Simplify sandbox flag assignment
You can replace the ternary with a direct boolean expression to satisfy the static analysis hint and improve readability.

-            item['isSandbox'] = True if config.environment_name != 'prod' else False
+            item['isSandbox'] = config.environment_name != 'prod'
🧰 Tools
🪛 Pylint (3.3.7)

[refactor] 91-91: The if expression can be replaced with 'test'

(R1719)

backend/compact-connect/tests/smoke/purchasing_privileges_smoke_tests.py (1)

321-332: Consider more robust response parsing.

The current implementation assumes UTF-8 BOM in the response (decode('utf-8-sig')). While this works, consider adding error handling for different response encodings.

-        response_data = json.loads(response.content.decode('utf-8-sig'))
+        try:
+            response_data = json.loads(response.content.decode('utf-8-sig'))
+        except UnicodeDecodeError:
+            # Fallback to standard UTF-8 if BOM is not present
+            response_data = json.loads(response.content.decode('utf-8'))
backend/compact-connect/lambdas/python/purchases/tests/unit/test_purchase_client.py (1)

146-146: Consider adding a test helper method for config reset.

While the current approach works, accessing the protected _Config() constructor could be made cleaner by adding a test helper method in the config module itself.

Consider adding a helper method in the cc_common.config module:

def reset_config_for_tests():
    """Reset config singleton for test isolation."""
    global config
    config = _Config()

This would make the test code cleaner and avoid the need for the suppression comment.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1be0b36 and 650286f.

📒 Files selected for processing (31)
  • backend/compact-connect/lambdas/nodejs/cloudfront-csp/index.js (2 hunks)
  • backend/compact-connect/lambdas/nodejs/cloudfront-csp/test/index.test.js (2 hunks)
  • backend/compact-connect/lambdas/python/common/cc_common/data_model/compact_configuration_client.py (1 hunks)
  • backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/api.py (2 hunks)
  • backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/common.py (2 hunks)
  • backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/record.py (2 hunks)
  • backend/compact-connect/lambdas/python/common/tests/resources/api/compact-configuration-response.json (0 hunks)
  • backend/compact-connect/lambdas/python/purchases/handlers/privileges.py (1 hunks)
  • backend/compact-connect/lambdas/python/purchases/handlers/transaction_history.py (4 hunks)
  • backend/compact-connect/lambdas/python/purchases/purchase_client.py (10 hunks)
  • backend/compact-connect/lambdas/python/purchases/tests/function/test_handlers/test_privilege_options.py (3 hunks)
  • backend/compact-connect/lambdas/python/purchases/tests/function/test_handlers/test_purchase_privileges.py (2 hunks)
  • backend/compact-connect/lambdas/python/purchases/tests/function/test_handlers/test_transaction_history.py (8 hunks)
  • backend/compact-connect/lambdas/python/purchases/tests/unit/test_purchase_client.py (10 hunks)
  • backend/compact-connect/stacks/api_stack/v1_api/api.py (1 hunks)
  • backend/compact-connect/stacks/api_stack/v1_api/api_model.py (1 hunks)
  • backend/compact-connect/stacks/api_stack/v1_api/credentials.py (3 hunks)
  • backend/compact-connect/stacks/transaction_monitoring_stack/transaction_history_processing_workflow.py (1 hunks)
  • backend/compact-connect/tests/app/test_api/test_purchases_api.py (1 hunks)
  • backend/compact-connect/tests/app/test_transaction_monitoring.py (1 hunks)
  • backend/compact-connect/tests/resources/snapshots/BetaFrontend-FrontendDeploymentStack-UI_DISTRIBUTION.json (1 hunks)
  • backend/compact-connect/tests/resources/snapshots/BetaFrontend-FrontendDeploymentStack-UI_DISTRIBUTION_LAMBDA_FUNCTION.json (1 hunks)
  • backend/compact-connect/tests/resources/snapshots/PURCHASE_PRIVILEGE_REQUEST_SCHEMA.json (1 hunks)
  • backend/compact-connect/tests/resources/snapshots/ProdFrontend-FrontendDeploymentStack-UI_DISTRIBUTION.json (1 hunks)
  • backend/compact-connect/tests/resources/snapshots/ProdFrontend-FrontendDeploymentStack-UI_DISTRIBUTION_LAMBDA_FUNCTION.json (1 hunks)
  • backend/compact-connect/tests/resources/snapshots/TestFrontend-FrontendDeploymentStack-UI_DISTRIBUTION.json (1 hunks)
  • backend/compact-connect/tests/resources/snapshots/TestFrontend-FrontendDeploymentStack-UI_DISTRIBUTION_LAMBDA_FUNCTION.json (1 hunks)
  • backend/compact-connect/tests/smoke/compact_configuration_smoke_tests.py (2 hunks)
  • backend/compact-connect/tests/smoke/config.py (1 hunks)
  • backend/compact-connect/tests/smoke/purchasing_privileges_smoke_tests.py (7 hunks)
  • backend/compact-connect/tests/smoke/smoke_tests_env_example.json (1 hunks)
💤 Files with no reviewable changes (1)
  • backend/compact-connect/lambdas/python/common/tests/resources/api/compact-configuration-response.json
🧰 Additional context used
🧬 Code Graph Analysis (4)
backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/api.py (1)
backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/common.py (1)
  • PaymentProcessorPublicFieldsSchema (43-51)
backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/record.py (1)
backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/common.py (1)
  • PaymentProcessorPublicFieldsSchema (43-51)
backend/compact-connect/stacks/api_stack/v1_api/credentials.py (2)
backend/compact-connect/stacks/persistent_stack/__init__.py (1)
  • PersistentStack (39-566)
backend/compact-connect/lambdas/python/common/cc_common/config.py (1)
  • compact_configuration_table (60-61)
backend/compact-connect/lambdas/python/purchases/tests/function/test_handlers/test_transaction_history.py (2)
backend/compact-connect/lambdas/python/purchases/handlers/transaction_history.py (1)
  • process_settled_transactions (13-128)
backend/compact-connect/lambdas/python/common/cc_common/config.py (1)
  • transaction_history_table (270-271)
🪛 Pylint (3.3.7)
backend/compact-connect/lambdas/python/purchases/handlers/privileges.py

[refactor] 91-91: The if expression can be replaced with 'test'

(R1719)

backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/common.py

[refactor] 43-43: Too few public methods (0/2)

(R0903)

backend/compact-connect/lambdas/python/purchases/tests/unit/test_purchase_client.py

[refactor] 134-134: Too many public methods (26/20)

(R0904)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: TestPython
🔇 Additional comments (49)
backend/compact-connect/tests/smoke/config.py (1)

55-62: Sandbox Authorize.Net credentials properties added appropriately
The new sandbox_authorize_net_api_login_id and sandbox_authorize_net_transaction_key properties follow the existing pattern, sourcing sandbox credentials from environment variables for smoke tests.

backend/compact-connect/tests/smoke/smoke_tests_env_example.json (1)

15-17: Include sandbox API credentials in example env file
Adding ENVIRONMENT_NAME, SANDBOX_AUTHORIZE_NET_API_LOGIN_ID, and SANDBOX_AUTHORIZE_NET_TRANSACTION_KEY ensures that smoke test environments can be configured with the placeholders needed by the new sandbox flows.

backend/compact-connect/lambdas/nodejs/cloudfront-csp/index.js (3)

176-178: Authorize.Net domains whitelisted for script-src
The https://jstest.authorize.net/ and https://js.authorize.net/ entries align with the Accept UI requirements and mirror the existing recaptcha pattern.


183-185: Authorize.Net domains added to script-src-elem
Consistent whitelisting across both inline and element script directives prevents CSP violations when loading Accept UI scripts.


222-224: Authorize.Net domains whitelisted for frame-src
Including the same domains in the frame source list is necessary for the Accept customer-hosted fields to render correctly.

backend/compact-connect/tests/resources/snapshots/TestFrontend-FrontendDeploymentStack-UI_DISTRIBUTION.json (1)

42-42: Snapshot update references new Lambda version
The CloudFront distribution snapshot now points to the updated CSPFunctionCurrentVersion—this matches the deployed Lambda changes and keeps tests in sync.

backend/compact-connect/tests/resources/snapshots/BetaFrontend-FrontendDeploymentStack-UI_DISTRIBUTION.json (1)

42-42: LGTM! Lambda function version updated for CSP enhancement.

The Lambda function reference change aligns with the CSP header updates to support Authorize.net domains for secure payment processing.

backend/compact-connect/tests/resources/snapshots/ProdFrontend-FrontendDeploymentStack-UI_DISTRIBUTION.json (1)

42-42: LGTM! Production environment aligned with Beta.

The Lambda function version update ensures consistent CSP behavior across environments for Authorize.net integration.

backend/compact-connect/lambdas/nodejs/cloudfront-csp/test/index.test.js (1)

89-90:

✅ Verification successful

Verify Authorize.net domain legitimacy and CSP directive appropriateness.

The additions of https://jstest.authorize.net/ and https://js.authorize.net/ to CSP directives support the new payment nonce workflow. Ensure these are the correct official Authorize.net domains and that both test and production domains are appropriately included.

Also applies to: 96-97, 135-136


🌐 Web query:

What are the official Authorize.Net JavaScript SDK domains for production and testing environments?

💡 Result:

When integrating the Authorize.Net JavaScript SDK, it's essential to use the correct domains for your environment to ensure proper functionality. The domains differ between the sandbox (testing) and production environments.

Sandbox (Testing) Environment:

  • Accept.js Library: For testing purposes, include the Accept.js library from the sandbox domain:
  <script type="text/javascript" src="https://jstest.authorize.net/v1/Accept.js" charset="utf-8"></script>

(community.developer.cybersource.com)

Production Environment:

  • Accept.js Library: For live transactions, use the production domain:
  <script type="text/javascript" src="https://js.authorize.net/v1/Accept.js" charset="utf-8"></script>

(community.developer.cybersource.com)

Ensure that your integration points to the appropriate domain based on your environment to maintain secure and accurate transaction processing.

Citations:


Authorize.Net SDK domains verified for CSP tests

Confirmed that https://jstest.authorize.net (sandbox) and https://js.authorize.net (production) are the official Accept.js domains. They’re correctly included in the CSP test at:

  • script-src (lines 89–90)
  • script-src-elem (lines 96–97)
  • frame-src (lines 135–136)

No further changes required.

backend/compact-connect/stacks/api_stack/v1_api/api.py (1)

136-136: LGTM! Proper integration of persistent stack for credential management.

The addition of the persistent_stack parameter to the Credentials constructor enables access to the compact configuration table, which is necessary for storing public payment processor credentials as outlined in the PR objectives.

backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/api.py (2)

13-13: LGTM! Correct import for payment processor public fields schema.

The import aligns with the new payment processing architecture that exposes public credentials to the frontend.


32-33:

✅ Verification successful

Verify schema consistency and field requirements.

The new fields look correctly implemented for the payment processor integration:

  • paymentProcessorPublicFields: Nested schema containing public credentials for frontend payment form generation
  • isSandbox: Boolean indicating sandbox environment status

Both fields are marked as required, which is appropriate since the frontend needs these values for payment processing.

Let me verify that the PaymentProcessorPublicFieldsSchema contains the expected fields:


🏁 Script executed:

#!/bin/bash
# Description: Verify the PaymentProcessorPublicFieldsSchema definition matches expected structure

# Search for the PaymentProcessorPublicFieldsSchema definition
ast-grep --pattern $'class PaymentProcessorPublicFieldsSchema($_):
  $$$'

Length of output: 1260


Schema Verified

The PaymentProcessorPublicFieldsSchema in backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/common.py defines both publicClientKey and apiLoginId as String(required=True, allow_none=False), which matches the integration requirements. The paymentProcessorPublicFields and isSandbox fields in api.py are correctly marked as required and non-nullable. No changes needed.

backend/compact-connect/tests/app/test_transaction_monitoring.py (1)

153-168: LGTM! Comprehensive test for workflow initialization changes.

The new test method correctly verifies that the transaction monitoring workflow's initialize state produces the expected JSON structure with:

  • Proper extraction of scheduledTime from EventBridge events
  • Correct initialization of compact and processedBatchIds
  • Appropriate result path configuration

The test follows the established pattern in the file and uses the helper method for token normalization.

backend/compact-connect/stacks/transaction_monitoring_stack/transaction_history_processing_workflow.py (1)

100-110: LGTM! Improved workflow initialization for replay-ability.

The changes correctly implement transaction processing replay-ability by:

  1. Extracting scheduled time: 'scheduledTime.$': '$.time' extracts the EventBridge event time
  2. Simplified initialization: Using Pass with parameters is cleaner than the previous Result.from_object approach
  3. Proper payload structure: Setting result_path='$.Payload' maintains consistency with downstream processing

This enables deterministic transaction collection windows for replay scenarios.

backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/record.py (1)

11-11: LGTM! Clean schema enhancement for payment processor integration.

The addition of the paymentProcessorPublicFields field is well-implemented with:

  • Proper import of the nested schema
  • Clear documentation explaining the field's purpose
  • Appropriate validation (required=False, allow_none=False)
  • Good alignment with the security enhancement to use payment nonces

Also applies to: 41-43

backend/compact-connect/tests/resources/snapshots/TestFrontend-FrontendDeploymentStack-UI_DISTRIBUTION_LAMBDA_FUNCTION.json (1)

5-5: Consistent CSP updates across environments.

The CSP header changes are identical to the BetaFrontend snapshot, ensuring consistent Authorize.Net domain allowlisting across all environments.

backend/compact-connect/tests/resources/snapshots/ProdFrontend-FrontendDeploymentStack-UI_DISTRIBUTION_LAMBDA_FUNCTION.json (1)

5-5: Production environment CSP updates complete the consistent deployment.

The CSP header changes match the other environment snapshots, completing the consistent Authorize.Net domain allowlisting across Beta, Test, and Production environments.

backend/compact-connect/lambdas/python/purchases/tests/function/test_handlers/test_privilege_options.py (4)

10-11: LGTM: Well-defined test constants.

The mock constants are clearly named and will be consistently used throughout the test file.


17-24: LGTM: Proper test setup with mock payment processor fields.

The test setup correctly includes the new payment processor public fields in the compact configuration, which aligns with the broader payment processor integration changes.


49-65: LGTM: Test assertion correctly validates jurisdiction option structure.

The hardcoded expected structure matches the test setup and includes all necessary jurisdiction fields.


83-99: LGTM: Comprehensive compact option validation.

The test assertion correctly validates the new payment processor public fields and sandbox flag alongside existing compact configuration fields.

backend/compact-connect/tests/smoke/compact_configuration_smoke_tests.py (3)

6-6: LGTM: Proper import of configuration.

The import of config module enables access to sandbox credentials for testing.


274-332: LGTM: Well-implemented smoke test for payment processor credentials.

The test function properly:

  • Creates a test compact admin user with appropriate permissions
  • Uses sandbox credentials from configuration
  • Includes proper error handling and validation
  • Cleans up test resources in the finally block
  • Uses appropriate timeout for external API calls

336-339: Verify if commented tests are intentional.

The existing smoke tests are commented out, leaving only the new payment processor test active. This might be intentional for focused testing during development.

Is this temporary for development/testing purposes, or should the other smoke tests remain active?

backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/common.py (2)

12-13: LGTM: Well-defined payment processor type enum.

The enum provides a consistent way to reference the Authorize.Net payment processor type across the codebase.


43-51: LGTM: Appropriate schema for payment processor public fields.

The schema correctly defines the public fields needed for client-side payment form generation. The static analysis warning about too few public methods is a false positive - data schemas don't need multiple public methods.

🧰 Tools
🪛 Pylint (3.3.7)

[refactor] 43-43: Too few public methods (0/2)

(R0903)

backend/compact-connect/lambdas/python/common/cc_common/data_model/compact_configuration_client.py (1)

189-215: LGTM! Well-implemented method for storing Authorize.Net public credentials.

The implementation follows best practices:

  • Proper validation by checking compact configuration existence before update
  • Uses UPDATE with SET to avoid overwriting other configuration fields
  • Includes appropriate logging for debugging
  • Clear documentation and type hints
backend/compact-connect/stacks/api_stack/v1_api/credentials.py (2)

26-44: LGTM! Proper integration with persistent stack for compact configuration access.

The constructor changes correctly:

  • Accept the persistent_stack parameter with proper typing
  • Set the environment variable from the persistent stack's table name
  • Pass the parameter to the helper method for permission configuration

46-57: LGTM! Correct permission configuration for compact configuration table access.

The method properly grants read/write permissions to the Lambda handler for accessing the compact configuration table, enabling storage of payment processor public credentials.

backend/compact-connect/lambdas/python/purchases/handlers/transaction_history.py (3)

28-37: LGTM! Proper parameter handling for scheduledTime.

The scheduledTime parameter is correctly extracted from the event and the documentation is updated appropriately.


42-47: LGTM! Improved replay-ability with scheduled time anchoring.

The time calculation correctly uses the scheduled time instead of current time, enabling consistent transaction retrieval windows for replay scenarios. The use of datetime.fromisoformat properly handles the ISO format from EventBridge.


87-87: LGTM! Proper preservation of scheduledTime for workflow continuity.

Preserving the scheduledTime in the response ensures consistent time anchoring across multiple workflow iterations.

backend/compact-connect/lambdas/python/purchases/tests/function/test_handlers/test_transaction_history.py (4)

28-28: LGTM! Proper mock constant for scheduled time testing.

The MOCK_SCHEDULED_TIME constant uses the correct ISO format expected from EventBridge.


141-150: LGTM! Consistent event structure updates for scheduledTime.

Both event creation methods properly include the scheduledTime parameter using the mock constant, ensuring test consistency.


200-208: LGTM! Comprehensive test assertion updates for scheduledTime.

All test assertions are properly updated to expect the scheduledTime field in responses, ensuring complete test coverage of the new functionality.

Also applies to: 350-350, 418-418, 441-441


299-334: LGTM! Excellent addition of idempotency test.

The new test properly verifies that repeated invocations with identical events don't create duplicate transaction records, which is crucial for replay-ability scenarios. The test setup and assertions are appropriate.

backend/compact-connect/lambdas/python/purchases/tests/function/test_handlers/test_purchase_privileges.py (1)

36-38: LGTM! Test data correctly updated for opaque payment data.

The test constants and request body structure have been properly updated to use opaque payment data instead of raw card details, aligning with the new payment processing approach.

Also applies to: 65-65

backend/compact-connect/tests/smoke/purchasing_privileges_smoke_tests.py (1)

49-51: Well-structured test enhancements for payment processor integration.

The test correctly:

  • Ensures payment processor credentials are uploaded before testing
  • Verifies the isSandbox flag is set appropriately
  • Validates that public payment fields are properly exposed in the API response

Also applies to: 74-74, 88-104

backend/compact-connect/lambdas/python/purchases/purchase_client.py (2)

323-330: Verify that removing billing address doesn't impact fraud prevention.

The implementation correctly uses opaque data, but billing address has been removed. Please ensure that:

  1. Authorize.Net's Accept UI captures billing address on the frontend if needed for AVS checks
  2. Your fraud prevention rules don't require billing address data

970-987: Excellent error handling for credential storage.

The implementation properly handles the edge case where compact configuration doesn't exist, providing clear guidance to configure fees before uploading credentials.

backend/compact-connect/lambdas/python/purchases/tests/unit/test_purchase_client.py (9)

3-3: LGTM! Imports properly added for AWS mocking.

The addition of os, boto3, and moto.mock_aws imports is appropriate for the new DynamoDB table setup in tests.

Also applies to: 7-10


58-64: LGTM! Mock constants properly defined for opaque payment data.

The new constants MOCK_DATA_DESCRIPTOR and MOCK_DATA_VALUE correctly represent the opaque payment token structure, and MOCK_PUBLIC_CLIENT_KEY is appropriately defined for the merchant details response.


85-85: LGTM! Order information correctly updated to use opaque data.

The function now returns the proper structure with opaqueData containing dataDescriptor and dataValue, aligning with the PR's security improvements.


133-166: Test setup properly implements DynamoDB mocking with appropriate cleanup.

The setUp method correctly creates a DynamoDB table for compact configuration and ensures cleanup with addCleanup. This prevents test pollution and aligns with the new requirement for compact configuration presence.

🧰 Tools
🪛 Pylint (3.3.7)

[refactor] 134-134: Too many public methods (26/20)

(R0904)


340-342: LGTM! Assertions correctly updated for opaque payment data.

The test properly verifies that the opaque data fields (dataDescriptor and dataValue) are being passed to the Authorize.Net SDK instead of raw card data, implementing the security improvements.


710-712: LGTM! Helper method properly sets up compact configuration.

The _when_compact_configuration_exists method correctly uses the test data generator to create the necessary compact configuration in DynamoDB.


714-722: LGTM! Response correctly includes public client key.

The mock response properly includes the publicClientKey field, which is necessary for the frontend to generate the payment collection form using Authorize.Net's Accept UI solution.


824-853: Excellent test coverage for missing compact configuration edge case.

The test properly validates that the system throws a clear, user-friendly error message when attempting to store payment credentials without a compact configuration. The error message provides actionable guidance to configure the compact fee values first.


134-134: Skip pylint warning about too many public methods.

Having 26 test methods in a test class is acceptable. Each test method focuses on a specific scenario, and splitting them across multiple classes would reduce code organization and readability.

🧰 Tools
🪛 Pylint (3.3.7)

[refactor] 134-134: Too many public methods (26/20)

(R0904)

@landonshumway-ia landonshumway-ia requested a review from jusdino June 6, 2025 16:53
Copy link
Collaborator

@jusdino jusdino left a comment

Choose a reason for hiding this comment

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

Great! No notes ✔️

@landonshumway-ia landonshumway-ia force-pushed the feat/authorize-net-payment-opaque-data branch from 8d85cec to 87ff589 Compare June 9, 2025 21:21
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 (1)
backend/compact-connect/lambdas/python/purchases/handlers/privileges.py (1)

90-91: Simplify the boolean assignment.

The logic is correct and aligns with the PR objective of exposing sandbox mode to the frontend. However, the conditional expression can be simplified.

Apply this diff to simplify the boolean assignment:

-            # we determine at run-time if the payment processor is running in sandbox mode
-            item['isSandbox'] = True if config.environment_name != 'prod' else False
+            # we determine at run-time if the payment processor is running in sandbox mode
+            item['isSandbox'] = config.environment_name != 'prod'
🧰 Tools
🪛 Pylint (3.3.7)

[refactor] 91-91: The if expression can be replaced with 'test'

(R1719)

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 8d85cec and 87ff589.

📒 Files selected for processing (32)
  • backend/compact-connect/lambdas/nodejs/cloudfront-csp/index.js (2 hunks)
  • backend/compact-connect/lambdas/nodejs/cloudfront-csp/test/index.test.js (2 hunks)
  • backend/compact-connect/lambdas/python/common/cc_common/data_model/compact_configuration_client.py (1 hunks)
  • backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/api.py (2 hunks)
  • backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/common.py (2 hunks)
  • backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/record.py (2 hunks)
  • backend/compact-connect/lambdas/python/common/tests/resources/api/compact-configuration-response.json (0 hunks)
  • backend/compact-connect/lambdas/python/purchases/handlers/privileges.py (1 hunks)
  • backend/compact-connect/lambdas/python/purchases/handlers/transaction_history.py (4 hunks)
  • backend/compact-connect/lambdas/python/purchases/purchase_client.py (10 hunks)
  • backend/compact-connect/lambdas/python/purchases/tests/function/test_handlers/test_privilege_options.py (3 hunks)
  • backend/compact-connect/lambdas/python/purchases/tests/function/test_handlers/test_purchase_privileges.py (2 hunks)
  • backend/compact-connect/lambdas/python/purchases/tests/function/test_handlers/test_transaction_history.py (8 hunks)
  • backend/compact-connect/lambdas/python/purchases/tests/unit/test_purchase_client.py (10 hunks)
  • backend/compact-connect/stacks/api_stack/v1_api/api.py (1 hunks)
  • backend/compact-connect/stacks/api_stack/v1_api/api_model.py (1 hunks)
  • backend/compact-connect/stacks/api_stack/v1_api/credentials.py (3 hunks)
  • backend/compact-connect/stacks/transaction_monitoring_stack/transaction_history_processing_workflow.py (1 hunks)
  • backend/compact-connect/tests/app/test_transaction_monitoring.py (1 hunks)
  • backend/compact-connect/tests/resources/snapshots/BetaFrontend-FrontendDeploymentStack-UI_DISTRIBUTION.json (1 hunks)
  • backend/compact-connect/tests/resources/snapshots/BetaFrontend-FrontendDeploymentStack-UI_DISTRIBUTION_LAMBDA_FUNCTION.json (1 hunks)
  • backend/compact-connect/tests/resources/snapshots/PURCHASE_PRIVILEGE_REQUEST_SCHEMA.json (1 hunks)
  • backend/compact-connect/tests/resources/snapshots/ProdFrontend-FrontendDeploymentStack-UI_DISTRIBUTION.json (1 hunks)
  • backend/compact-connect/tests/resources/snapshots/ProdFrontend-FrontendDeploymentStack-UI_DISTRIBUTION_LAMBDA_FUNCTION.json (1 hunks)
  • backend/compact-connect/tests/resources/snapshots/TestFrontend-FrontendDeploymentStack-UI_DISTRIBUTION.json (1 hunks)
  • backend/compact-connect/tests/resources/snapshots/TestFrontend-FrontendDeploymentStack-UI_DISTRIBUTION_LAMBDA_FUNCTION.json (1 hunks)
  • backend/compact-connect/tests/smoke/compact_configuration_smoke_tests.py (2 hunks)
  • backend/compact-connect/tests/smoke/config.py (1 hunks)
  • backend/compact-connect/tests/smoke/load_test_privilege_purchasing.py (5 hunks)
  • backend/compact-connect/tests/smoke/purchasing_privileges_smoke_tests.py (5 hunks)
  • backend/compact-connect/tests/smoke/smoke_common.py (2 hunks)
  • backend/compact-connect/tests/smoke/smoke_tests_env_example.json (1 hunks)
💤 Files with no reviewable changes (1)
  • backend/compact-connect/lambdas/python/common/tests/resources/api/compact-configuration-response.json
✅ Files skipped from review due to trivial changes (1)
  • backend/compact-connect/tests/smoke/config.py
🚧 Files skipped from review as they are similar to previous changes (27)
  • backend/compact-connect/tests/smoke/smoke_tests_env_example.json
  • backend/compact-connect/lambdas/nodejs/cloudfront-csp/index.js
  • backend/compact-connect/tests/resources/snapshots/TestFrontend-FrontendDeploymentStack-UI_DISTRIBUTION.json
  • backend/compact-connect/tests/app/test_transaction_monitoring.py
  • backend/compact-connect/lambdas/nodejs/cloudfront-csp/test/index.test.js
  • backend/compact-connect/tests/resources/snapshots/BetaFrontend-FrontendDeploymentStack-UI_DISTRIBUTION_LAMBDA_FUNCTION.json
  • backend/compact-connect/tests/resources/snapshots/BetaFrontend-FrontendDeploymentStack-UI_DISTRIBUTION.json
  • backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/record.py
  • backend/compact-connect/tests/resources/snapshots/ProdFrontend-FrontendDeploymentStack-UI_DISTRIBUTION.json
  • backend/compact-connect/tests/resources/snapshots/TestFrontend-FrontendDeploymentStack-UI_DISTRIBUTION_LAMBDA_FUNCTION.json
  • backend/compact-connect/tests/resources/snapshots/ProdFrontend-FrontendDeploymentStack-UI_DISTRIBUTION_LAMBDA_FUNCTION.json
  • backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/api.py
  • backend/compact-connect/stacks/api_stack/v1_api/api.py
  • backend/compact-connect/tests/resources/snapshots/PURCHASE_PRIVILEGE_REQUEST_SCHEMA.json
  • backend/compact-connect/stacks/api_stack/v1_api/credentials.py
  • backend/compact-connect/lambdas/python/purchases/tests/function/test_handlers/test_privilege_options.py
  • backend/compact-connect/lambdas/python/purchases/tests/function/test_handlers/test_transaction_history.py
  • backend/compact-connect/lambdas/python/purchases/tests/function/test_handlers/test_purchase_privileges.py
  • backend/compact-connect/stacks/transaction_monitoring_stack/transaction_history_processing_workflow.py
  • backend/compact-connect/lambdas/python/purchases/handlers/transaction_history.py
  • backend/compact-connect/lambdas/python/common/cc_common/data_model/compact_configuration_client.py
  • backend/compact-connect/tests/smoke/load_test_privilege_purchasing.py
  • backend/compact-connect/tests/smoke/smoke_common.py
  • backend/compact-connect/tests/smoke/compact_configuration_smoke_tests.py
  • backend/compact-connect/stacks/api_stack/v1_api/api_model.py
  • backend/compact-connect/tests/smoke/purchasing_privileges_smoke_tests.py
  • backend/compact-connect/lambdas/python/purchases/purchase_client.py
🧰 Additional context used
🧬 Code Graph Analysis (1)
backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/common.py (1)
backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/common.py (1)
  • CCEnum (180-190)
🪛 Pylint (3.3.7)
backend/compact-connect/lambdas/python/purchases/tests/unit/test_purchase_client.py

[refactor] 134-134: Too many public methods (26/20)

(R0904)

backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/common.py

[refactor] 43-43: Too few public methods (0/2)

(R0903)

backend/compact-connect/lambdas/python/purchases/handlers/privileges.py

[refactor] 91-91: The if expression can be replaced with 'test'

(R1719)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: TestPython
🔇 Additional comments (7)
backend/compact-connect/lambdas/python/common/cc_common/data_model/schema/compact/common.py (2)

12-14: LGTM! Well-structured enum addition.

The PaymentProcessorType enum properly extends CCEnum and follows the established naming conventions. This supports the transition to Authorize.Net opaque data handling.


43-51: LGTM! Essential schema for secure payment processing.

The PaymentProcessorPublicFieldsSchema correctly defines the required fields (publicClientKey and apiLoginId) needed for client-side payment form generation. This is a key component of the security improvement that eliminates backend handling of raw card data.

🧰 Tools
🪛 Pylint (3.3.7)

[refactor] 43-43: Too few public methods (0/2)

(R0903)

backend/compact-connect/lambdas/python/purchases/tests/unit/test_purchase_client.py (5)

58-64: LGTM! Proper mock data for secure payment testing.

The addition of mock constants for opaque data (MOCK_DATA_DESCRIPTOR, MOCK_DATA_VALUE) and public client key properly supports testing the new secure payment flow without exposing raw card data.


133-166: LGTM! Comprehensive AWS mocking infrastructure.

The addition of @mock_aws decorator and DynamoDB table setup/teardown provides proper test isolation and supports testing the new compact configuration validation logic.

🧰 Tools
🪛 Pylint (3.3.7)

[refactor] 134-134: Too many public methods (26/20)

(R0904)


85-85: LGTM! Secure payment data for testing.

The updated _generate_default_order_information() method now returns opaque data instead of raw card details, which aligns perfectly with the PR objective of enhancing payment security.


340-342: LGTM! Updated assertions for opaque data validation.

The test correctly validates that opaque data fields (dataDescriptor and dataValue) are properly passed to the Authorize.Net SDK instead of raw card data, ensuring the security improvements are working as expected.


824-853: LGTM! Essential test coverage for validation logic.

This new test ensures that credential validation fails when compact configuration doesn't exist, providing good coverage for the new validation workflow and clear error messaging to users.

Previously, if a transaction history collection job failed to process for
whatever reason (such as a service outage), it was incredibly difficult to run
the processing for that specific time period again. This change leverages the
fact that event bridge sends in the timestamp of the time in which the scheduled
task was triggered.

By going off of this time, rather than generating the timestamp in the lambda,
developers can simply rerun the failed step function execution, and it will
process all the transactions for that same time period. Due to the idempotent
nature of the transaction pk/sk design, we will never see duplicate transaction
records for the same transaction ids.
@landonshumway-ia landonshumway-ia force-pushed the feat/authorize-net-payment-opaque-data branch from f838ce8 to 3a12b3c Compare June 11, 2025 15:05
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 (4)
webroot/src/components/PrivilegePurchaseFinalize/PrivilegePurchaseFinalize.ts (4)

179-181: Prefer nullish-coalescing over logical OR for precise fallback

|| null will coerce falsy objects (e.g., {} as PaymentSdkConfig) to null, masking data that is merely “empty.”
Using ?? keeps the intent clear and only falls back when the value is null / undefined.

-get currentCompactPaymentSdkConfig(): PaymentSdkConfig | null {
-    return this.currentCompact?.fees?.paymentSdkConfig || null;
+get currentCompactPaymentSdkConfig(): PaymentSdkConfig | null {
+    return this.currentCompact?.fees?.paymentSdkConfig ?? null;
}

280-285: Add explicit parameter & return types to shouldUseMilitaryRate

The helper currently accepts any, weakening type-safety and IntelliSense.
A minimal structural type is enough to clarify intent and catch future regressions.

-shouldUseMilitaryRate(feeConfig) {
+shouldUseMilitaryRate(feeConfig: { militaryRate?: number }): boolean {
     const { militaryRate } = feeConfig || {};
     const hasMilitaryRate = Boolean(militaryRate || militaryRate === 0);
 
     return Boolean(hasMilitaryRate && this.licensee?.isMilitaryStatusActive());
 }

300-318: Narrow opaqueData parameter type to match Accept UI contract

opaqueData arrives from Authorize.Net and has a well-defined shape ({ dataDescriptor: string; dataValue: string }).
Keeping it as object forfeits type safety and makes downstream mistakes harder to spot.

-import type { AcceptUiResponse } from '@components/PrivilegePurchaseAcceptUI/PrivilegePurchaseAcceptUI.vue';
+import type {
+  AcceptUiResponse,
+  OpaqueData /* <- interface exported from Accept UI component */
+} from '@components/PrivilegePurchaseAcceptUI/PrivilegePurchaseAcceptUI.vue';
 ...
-async handleSubmitOverride(opaqueData: object): Promise<void> {
+async handleSubmitOverride(opaqueData: OpaqueData): Promise<void> {

332-335: Scroll error message into view after backend failure

In the backend-error branch the form message is set but not scrolled into view, unlike acceptUiErrorResponse.
This small UX tweak keeps feedback consistent.

             } else if (purchaseServerEvent?.message) {
                 this.isFormError = true;
                 this.formErrorMessage = purchaseServerEvent?.message;
+                await nextTick();
+                document
+                  .getElementById('button-row')
+                  ?.scrollIntoView({ behavior: 'smooth', block: 'center' });
             }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between d9bdbdf and 9db07fd.

📒 Files selected for processing (4)
  • webroot/src/components/PrivilegePurchaseAttestation/PrivilegePurchaseAttestation.ts (3 hunks)
  • webroot/src/components/PrivilegePurchaseFinalize/PrivilegePurchaseFinalize.ts (7 hunks)
  • webroot/src/locales/en.json (1 hunks)
  • webroot/src/locales/es.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • webroot/src/components/PrivilegePurchaseAttestation/PrivilegePurchaseAttestation.ts
  • webroot/src/locales/en.json
  • webroot/src/locales/es.json
🧰 Additional context used
🧠 Learnings (1)
webroot/src/components/PrivilegePurchaseFinalize/PrivilegePurchaseFinalize.ts (1)
Learnt from: jsandoval81
PR: csg-org/CompactConnect#847
File: webroot/src/components/PrivilegePurchaseFinalize/PrivilegePurchaseFinalize.ts:195-197
Timestamp: 2025-06-11T19:43:08.839Z
Learning: For the MVP phase, the team prefers to surface the raw "undefined" (or similar) when the compact commission fee is missing, rather than showing a misleading fallback such as "0.00"; the server-side validation will catch invalid values.
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: TestPython
  • GitHub Check: CheckWebroot

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: 1

🔭 Outside diff range comments (1)
webroot/src/components/PrivilegePurchaseFinalize/PrivilegePurchaseFinalize.ts (1)

314-346: 🛠️ Refactor suggestion

Add a catch-all error branch for unexpected server responses

If purchaseServerEvent is null/undefined, or the backend changes the success message, the user receives no feedback and the form stays in a loading state. Guard against this by adding a default error handler and relying on a more robust success signal than a free-text string comparison.

-            } else if (purchaseServerEvent?.message) {
+            } else if (purchaseServerEvent?.message) {
                 this.isFormError = true;
                 this.formErrorMessage = purchaseServerEvent?.message;
                 await this.scrollIntoView('button-row');
+            } else {
+                // Fallback for network / unexpected errors
+                this.isFormError = true;
+                this.formErrorMessage = this.$t('common.unexpectedError');
+                await this.scrollIntoView('button-row');
             }

Consider having the backend return a boolean success flag (or HTTP status) to avoid brittle string comparisons.

🧹 Nitpick comments (2)
webroot/src/components/PrivilegePurchaseFinalize/PrivilegePurchaseFinalize.ts (2)

280-285: Type the feeConfig parameter for better IntelliSense and safety

Explicitly typing the argument avoids any, documents expected shape, and surfaces mistakes during refactors.

-    shouldUseMilitaryRate(feeConfig) {
+    shouldUseMilitaryRate(
+        feeConfig: { militaryRate?: number; baseRate?: number } | null | undefined
+    ): boolean {

209-218: Reuse the existing privilegeCount getter to reduce duplication

creditCardFeesTotal manually recalculates the privilege count. Leveraging the computed property keeps the logic in one place.

-        const numPrivileges = this.selectedStatePurchaseDataList?.length || 0;
+        const numPrivileges = this.privilegeCount;
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 9db07fd and c6d838c.

📒 Files selected for processing (1)
  • webroot/src/components/PrivilegePurchaseFinalize/PrivilegePurchaseFinalize.ts (8 hunks)
🧰 Additional context used
🧠 Learnings (1)
webroot/src/components/PrivilegePurchaseFinalize/PrivilegePurchaseFinalize.ts (1)
Learnt from: jsandoval81
PR: csg-org/CompactConnect#847
File: webroot/src/components/PrivilegePurchaseFinalize/PrivilegePurchaseFinalize.ts:195-197
Timestamp: 2025-06-11T19:43:08.839Z
Learning: For the MVP phase, the team prefers to surface the raw "undefined" (or similar) when the compact commission fee is missing, rather than showing a misleading fallback such as "0.00"; the server-side validation will catch invalid values.
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: TestPython
  • GitHub Check: CheckWebroot

Copy link
Collaborator

@rmolinares rmolinares left a comment

Choose a reason for hiding this comment

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

Nice job! Minor questions / comments but I also wanted to mention that I'm not able to view the "Purchase successful" screen because the suggested CC info in the QA notes trigger an error and redirect back to the "Payment Summary" screen.

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

🔭 Outside diff range comments (1)
webroot/src/components/PrivilegePurchaseFinalize/PrivilegePurchaseFinalize.ts (1)

306-346: 🛠️ Refactor suggestion

Guarantee spinner cleanup and capture network errors

startFormLoading() is called before the async dispatch, but endFormLoading() is only reached on the success path. If the action throws (network error, unhandled 5xx, etc.) the loading state never resets and the user is stuck.

-            this.startFormLoading();
-            ...
-            const purchaseServerEvent = await this.$store.dispatch('user/postPrivilegePurchases', serverData);
-            this.endFormLoading();
+            this.startFormLoading();
+            let purchaseServerEvent;
+            try {
+                purchaseServerEvent = await this.$store.dispatch(
+                    'user/postPrivilegePurchases',
+                    serverData
+                );
+            } catch (err) {
+                purchaseServerEvent = { message: err?.message ?? 'Unexpected error' };
+            } finally {
+                this.endFormLoading();
+            }

Placing endFormLoading() in finally ensures the UI recovers regardless of how the promise resolves.

♻️ Duplicate comments (1)
webroot/src/components/PrivilegePurchaseFinalize/PrivilegePurchaseFinalize.ts (1)

179-185: || still discards legitimate zero-value commission fees

Using the logical-OR fallback converts a valid 0 fee into null, which in turn causes totalCompactCommissionFee (lines 191-199) to ignore the fee entirely. The same concern was raised on an earlier commit and left unresolved for domain reasons, so I’m just flagging for visibility.

🧹 Nitpick comments (2)
webroot/src/components/PrivilegePurchaseFinalize/PrivilegePurchaseFinalize.ts (2)

280-285: Add an explicit type for feeConfig

shouldUseMilitaryRate receives an untyped feeConfig, which weakens type-safety and IntelliSense. Declare it as the concrete fee-config interface to surface missing properties at compile time.

-shouldUseMilitaryRate(feeConfig): boolean {
+shouldUseMilitaryRate(feeConfig: PrivilegePurchaseOption['fees'][string]): boolean {

297-304: Retrieve the element after nextTick to avoid stale refs

scrollIntoView fetches the DOM node before await nextTick(), so updates triggered earlier in the call stack might replace the element, leaving you with a stale reference. Move the query after the tick.

-const formMessageElement = document.getElementById(id);
-
-if (formMessageElement?.scrollIntoView) {
-    await nextTick();
-    formMessageElement?.scrollIntoView({ behavior: 'smooth', block: 'center' });
-}
+await nextTick();
+const el = document.getElementById(id);
+el?.scrollIntoView({ behavior: 'smooth', block: 'center' });
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e602e6b and e0c8e72.

📒 Files selected for processing (2)
  • webroot/src/components/PrivilegePurchaseFinalize/PrivilegePurchaseFinalize.ts (8 hunks)
  • webroot/src/locales/es.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • webroot/src/locales/es.json
🧰 Additional context used
🧠 Learnings (1)
webroot/src/components/PrivilegePurchaseFinalize/PrivilegePurchaseFinalize.ts (1)
Learnt from: jsandoval81
PR: csg-org/CompactConnect#847
File: webroot/src/components/PrivilegePurchaseFinalize/PrivilegePurchaseFinalize.ts:195-197
Timestamp: 2025-06-11T19:43:08.839Z
Learning: For the MVP phase, the team prefers to surface the raw "undefined" (or similar) when the compact commission fee is missing, rather than showing a misleading fallback such as "0.00"; the server-side validation will catch invalid values.
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: CheckWebroot
  • GitHub Check: TestPython

@jsandoval81 jsandoval81 requested a review from rmolinares June 13, 2025 17:21
@jsandoval81
Copy link
Collaborator

@jlkravitz This is ready for your review.

FYI the unresolved comments from @rmolinares above are actually resolved, but neither him nor I have the ability to mark them resolved. If you're able to then it's a green light to do so.

Copy link
Collaborator

@jlkravitz jlkravitz left a comment

Choose a reason for hiding this comment

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

a few small comments/questions, but generally looks good!

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

♻️ Duplicate comments (1)
backend/compact-connect/lambdas/python/purchases/tests/unit/test_purchase_client.py (1)

162-166: Moto waiter still unsupported – this teardown will crash
Moto does not implement get_waiter('table_not_exists'), so line 165 raises UnknownOperationError, breaking test cleanup.
Same issue was flagged previously and is still unresolved.

-        waiter = self._compact_configuration_table.meta.client.get_waiter('table_not_exists')
-        waiter.wait(TableName=self._compact_configuration_table.name)
+        # Moto has no waiter implementation; a short sleep is enough
+        import time
+        time.sleep(0.1)
🧹 Nitpick comments (1)
backend/compact-connect/lambdas/python/purchases/tests/unit/test_purchase_client.py (1)

841-851: Assertion could be simplified & made less fragile

CCInvalidRequestException already stringifies to the message; asserting on str(context.exception) avoids reaching into a .message attribute (which isn’t standard on Python exceptions).

-            str(context.exception.message),
+            str(context.exception),
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between fe0b287 and 609c348.

📒 Files selected for processing (3)
  • backend/compact-connect/lambdas/python/purchases/tests/function/test_handlers/test_transaction_history.py (8 hunks)
  • backend/compact-connect/lambdas/python/purchases/tests/unit/test_purchase_client.py (10 hunks)
  • backend/compact-connect/tests/smoke/compact_configuration_smoke_tests.py (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/compact-connect/tests/smoke/compact_configuration_smoke_tests.py
  • backend/compact-connect/lambdas/python/purchases/tests/function/test_handlers/test_transaction_history.py
🧰 Additional context used
🪛 Pylint (3.3.7)
backend/compact-connect/lambdas/python/purchases/tests/unit/test_purchase_client.py

[refactor] 135-135: Too many public methods (26/20)

(R0904)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: CheckWebroot
  • GitHub Check: TestPython
🔇 Additional comments (3)
backend/compact-connect/lambdas/python/purchases/tests/unit/test_purchase_client.py (3)

151-160: Possible hidden dependency on env var COMPACT_CONFIGURATION_TABLE_NAME

create_compact_configuration_table() extracts the table name from os.environ.
If a caller (or TstLambdas) forgets to prime this variable, tests will explode with KeyError.
Consider supplying a default (os.getenv('…', 'compact-configuration')) or asserting its presence during setUp to fail fast with a clearer error.


711-713: Static access to TestDataGenerator may be brittle

self.test_data_generator is set to the class TestDataGenerator, then called without instantiation.
If put_default_compact_configuration_in_configuration_table is an instance method, this will raise TypeError.
Double-check that the helper is a @staticmethod/@classmethod, or instantiate:

self.test_data_generator = TestDataGenerator()  # if instance method

341-344: Opaque-data assertions look good

New assertions confirm that the SDK receives the expected dataDescriptor and dataValue; this tightens coverage around the tokenised payment flow.

Copy link
Collaborator

@jlkravitz jlkravitz left a comment

Choose a reason for hiding this comment

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

@isabeleliassen This is good to merge!

@isabeleliassen isabeleliassen merged commit 426f1d7 into csg-org:development Jun 18, 2025
5 checks passed
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.

authorize.net update for compliance BE authorize.net update for compliance FE
6 participants