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

Stock Handling #18

Open
IncreaseComputers opened this issue Apr 25, 2022 · 8 comments
Open

Stock Handling #18

IncreaseComputers opened this issue Apr 25, 2022 · 8 comments
Assignees
Labels
enhancement New feature or request

Comments

@IncreaseComputers
Copy link

I'm looking to implement stock handling for order s/ basket items - handling the stock is fine the problem I'm having is catching basket quantity changes to adjust stock levels, any ideas or suggestions on doing this?

@IncreaseComputers
Copy link
Author

I think the item validator would do the job if it could be raised on item deletes/ basket clears

@dinoperovic
Copy link
Owner

@IncreaseComputers could you perhaps use Django's post_save and post_delete signals on the BaksetItem model to sync with your stock management?

The basket item validator is used just for validating the item, it is not aware of deletes.

@IncreaseComputers
Copy link
Author

Signals wont work as getting the original values from the objects is problematic - Ie in basket save has the quantity changed? what was the old quantity what is the new quantity? - I have implemented a "stock _handler" override similar to the validators and hooked into it at various points in basket and basket item to deal with changes - it passes a operation "delete" / "add" /"update" the original object and the changed fields - it works but it means overriding core code making it more difficult to maintain

@dinoperovic
Copy link
Owner

I see what you're saying. I suppose you could swap the basket models and add the additional field that keeps track of the "previous quantity" on the basket item. You could do this using the swappable models feature:
https://django-salesman.readthedocs.io/en/latest/advanced/swappable_models.html

The thing with stock handling is that it can differ from the shop implementation making it hard to put specific logic into the core project. Maybe having dedicated signals for whenever an item is added/updated/deleted on the basket would solve this.

I would also consider a different approach to stock management, one where it does not tie to the basket directly.
I had previously used a system like this:

  • In a payment method, when checkout is called, create a stock reservation object for the basket
  • Add logic to the validate_basket method on payment that first checks if all items are available (taking reservations into account)
  • Once the payment is completed, commit that stock reservation. If payment fails, drop the reservation
  • Optionally add a basket modifier that checks item availability based on reservations so that it can be communicated to the customer before checkout

This way you're not updating the stock on every basket item add/remove, but rather when the intent to buy the items is created.
Also, users tend to add items to the basket and leave the shop, with your approach you would have decreased the stock for that item indefinitely -- this can, of course, be handled by implementing an abandoned cart feature, but you see my point.

@IncreaseComputers
Copy link
Author

one of the problems (which is specific to my implementation) is that I'm selling memberships - which have a limit - so I have to follow the basket rather than the order - I cant oversell... - I will stick with my overrides for now - I'm planning to also implement the methods into the order to also convert a "reservation" to a completed stock adjustment.

@IncreaseComputers
Copy link
Author

To handle the abandoned item I have added an "expiry" timer to the item which removes it from the cart after a specified time

@dinoperovic
Copy link
Owner

dinoperovic commented Apr 29, 2022

@IncreaseComputers I believe you would still avoid overselling in my example by raising ValidationError in validate_basket method on the payment if any one of the items is not available.

Either way, here's an example implementation using Django signals without overriding the basket item model:

from django.dispatch import receiver
from django.db.models.signals import post_delete, post_init, post_save

from salesman.core.utils import get_salesman_model

BasketItem = get_salesman_model("BasketItem")


@receiver(post_init, sender=BasketItem)
def post_init_item(sender, instance, **kwargs):
    # Remember current quantity on the instance
    instance._current_quantity = 0 if instance.pk is None else instance.quantity


@receiver(post_save, sender=BasketItem)
def post_save_item(sender, instance, **kwargs):
    quantity_diff = instance.quantity - instance._current_quantity
    if quantity_diff > 0:
        print(f"Decrease {instance.product} stock by {quantity_diff}")
    elif quantity_diff < 0:
        print(f"Increase {instance.product} stock by {quantity_diff * -1}")


@receiver(post_delete, sender=BasketItem)
def post_delete_item(sender, instance, **kwargs):
    print(f"Increase {instance.product} stock for {instance.quantity}")

You can of course override the __init__, save and delete methods on basket item directly using swappable models.

I am considering adding the item_quantity_changed signal that would basically do this by default, but I'm still not sure if it would be helpful for any other cases.

@pablondrina
Copy link

pablondrina commented Apr 29, 2022 via email

@dinoperovic dinoperovic added the enhancement New feature or request label May 9, 2022
@dinoperovic dinoperovic self-assigned this May 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants