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

Add tax collection and blocked countries processing #166

Open
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

jkachel
Copy link
Collaborator

@jkachel jkachel commented Nov 4, 2024

What are the relevant tickets?

Closes mitodl/hq#5766

Description (What does it do?)

Adds a basket_add hook that is fired before a user adds an item to their basket, so we can perform tasks based on the user and product being added.

Adds a wrapper plugin to pull in some data that other plugins will need and finish setting up the basket object. (At the moment, this means geolocating the user for tax lookup and blocked countries reasons.) Geolocation works based on geolocating via IP and by considering the user's profile.

Adds a check for blocked countries that runs when an item is added to the basket. If the user belongs to a country that we've blocked either globally in UE or for a particular product, the check raises an exception and basket processing stops.

Adds a check for tax assessment for the user. If the user is in a country that assesses tax, we then flag the basket as being taxable with the rate that matches for the user.

Pulls in the geoip code from ol-django for geolocation, adds support for field mappings in the APISIX middleware, and adds a few other necessary things for this process. It also adds the necessary data to orders so tax is collected through the order process, and updates the display of the orders in Django Admin to make them more usable.

Screenshots

Completed order in Django Admin (displays the new fields/groupings):

image

Cart with some updates to show tax/etc.:

image

How can this be tested?

You will need to import the MaxMind GeoLite2 databases. See the documentation in the ol-django geoip app for instructions.

For best results, simply add a "country code" to your user profile manually through the Django Admin.

  1. Add a blocked country and a tax rate using the admin interface. Blocked countries can be for a particular product or for the entire system, so you should configure both.
  2. Configure test accounts (or equivalent): one that should not hit any blocks/checks, one that should hit the blocked countries check globally, and one that should hit the blocked countries check for a particular product. Also, configure one that will not hit the block but will be assessed tax.
  3. Attempt to check out in each scenario. Your results should match the truth table below. Note that the cart test mule won't handle the error gracefully so you will likely need to check in devtools - you should get HTTP 451 Unavailable for Legal Reasons for blocked countries.
  4. For the scenario that involves tax, you should additionally see tax assessed in the cart, and you should be charged tax in the order. Tax should be applied across the entire order.

For completed orders that involve tax:

  • You should see the tax appear in the CyberSource payment screens.
  • The order as displayed in the Django Admin should display the calculated tax amounts.
  • Discounts should be applied before tax - i.e. we collect tax on the discounted amount.
  • The line should also display the correct amount of tax.
  • The transaction should also display the correct totals.

For completed orders that involve discounts:

  • You should see new fields in the Django Admin for the order that break out the total amount of discount that was applied.

@jkachel jkachel added the product:unified-ecommerce Issues related to the Unified Ecommerce project label Nov 4, 2024
- Add the mitol-django-geoip library
- Add a user_profile model so we can cache some additional user info from Keycloak
- Update the APISIX middleware to pull additional data into the profile when it exists
- Add some fields to the basket to track user location data (since we'll need it elsewhere)
- Adds some APIs for determining the location of the user
- Adds the TaxRate and BlockedCountry models
- Adds a test setting (force profile country)
- Adds some factories
- Formatted some stuff that's unrelated (inadvertently but it's probably a good idea anyway)
- Added PLR0913 to test ignore list because tired of seeing it
- Added tests for location determination stuff
- Added some dataclasses for location metadata
- Updated basket location storage to split out tax and blocked country geolocations (since they might be different)
- Finished up tests
- Updated the blanket ruff ignore list to add line length to migrations

The basket location stuff will need to migrate into the order too but haven't done that yet.
- Renamed "authentication" to "users" (it really didn't have anything to do with auth)
- Adjusted the hooks for basket_add to fix some circular import issues and cause less database hits
- Updated the Order model to match the Basket for user data and tax rate additions
- Updated TaxRate and BlockedCountry to use SoftDelete
- Added at least one point where it should run the location-based checks - adding an item to cart will now actually check blocked countries and taxes now
- Added a bunch of helper functions for price calculation in the basket
- Added py-moneyed for said price calculations
- Updated the cart to show tax if it's been calculated
@jkachel jkachel force-pushed the jkachel/5766-tax-collection-blocked-countries-proc branch from 2ca96bc to ff8044c Compare November 4, 2024 21:32
- Moved a migration so it's not out of order now
- Fixed some stuff that got munged up by doing the merge
- Ran ruff and fixed a bunch of issues (ruff config is not the best at the moment, need to fix that too, later)
- Updated the pyproject.toml to ignore some stuff that we're unlikely to change
@jkachel jkachel force-pushed the jkachel/5766-tax-collection-blocked-countries-proc branch from 23c8789 to 04064ce Compare November 4, 2024 22:17
@jkachel jkachel added the Work in Progress Not done yet. label Nov 4, 2024
… order properly

- Add some more columns to the test mule cart page
- Fix some places where we're using floats for money
- Update the Order to pull in the tax and blocked countries check fields
- Add some more helpers to get Money objects out when that makes more sense than a Decimal
- Bump versions of some stuff so geoip has migrations, etc.
Using CountryField makes Spectacular expand the enum and since they're the same it emits a warning.
…or testing

- The logic that was in CustomerVerificationHooks is now in payments/api.py - this pulls the logic out into a more reusable place and also makes it much easier to write tests
- Add tests for the various steps of the basket_add hook
- Fix a couple of logic errors that came up in testing
… UserProfile, fix up order tax collection

Not done: this will also require a new version of payment_gateway and the tax collection needs a bit of help still
Also adds a cancel button to the checkout interstitial so you can stop the form submit
… dependency on py-moneyed

if i have to quantize the decimal then py-moneyed doesn't really help any
@jkachel jkachel force-pushed the jkachel/5766-tax-collection-blocked-countries-proc branch from cd536bd to 6029d40 Compare November 8, 2024 13:48
@jkachel jkachel marked this pull request as ready for review November 12, 2024 19:52
@jkachel jkachel added Needs Review An open Pull Request that is ready for review and removed Work in Progress Not done yet. labels Nov 12, 2024
@cp-at-mit cp-at-mit self-assigned this Nov 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Review An open Pull Request that is ready for review product:unified-ecommerce Issues related to the Unified Ecommerce project
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants