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

Merchandise sales moneybird integration #3464

Closed
wants to merge 30 commits into from

Conversation

tmgdejong
Copy link
Contributor

@tmgdejong tmgdejong commented Oct 30, 2023

Closes #1657.

Adds a way to sell merchandise via the site, such that the merchandise sale gets registered automatically and will be processed in Moneybird.

It works using Thadmin, where a board member can enter a Merchandise Sale shift to sell merchandise. this shift has as product list a unique list, containing all merchandise items. This list is generated and updated automatically.
Merchandise Sale shifts are also created automatically, on a daily basis, and on creating a new shift, all old Merchandise Sale shifts get locked, or deleted if there are 0 items sold.
Just like a normal shift sale, a payment and an external invoice get created, but next to this, a general journal document gets created as well. This allows us in Moneybird to add a general journal document, which creates a credit transaction on the merchandise stock ledger, linked with a debit transaction on the merchandise costs ledger.

2 'problems' that are still in the code:
- In the migration for a merchandise item, even though Python code is ran to retain our current merchandise items, this does not seem to work yet.
- When a general journal document is 'updated', we now remove it and simply create a new one. This should be implemented the same way as with external invoices, where an attribute id is saved.

@JobDoesburg @DeD1rk @nvoers let me know what you think!

author Thijs de Jong <[email protected]> 1697580318 +0200
committer movieminer <[email protected]> 1697613494 +0200

parent cb8b4d9
author Thijs de Jong <[email protected]> 1697580318 +0200
committer movieminer <[email protected]> 1697613467 +0200

Add purchase price to merchandise

Update settings.py

Update models.py

Update models.py

Update payables.py

Update admin.py

Update models.py

Update models.py

Update settings.py

Update models.py

Update payables.py

Update models.py

Add purchase price to merchandise

Update settings.py

Update models.py

Update payables.py

Update admin.py

Update models.py

Update settings.py

Update models.py

Update payables.py

Update models.py

Add purchase price to merchandise
…svthalia/concrexit into merchandise-sales-moneybird-integration
@DeD1rk
Copy link
Member

DeD1rk commented Oct 30, 2023

I don't really see an advantage in using sales here, as opposed to making e.g. a MerchandiseSale payable model. If we had a way to make miscellaneous payment requests (#3453) would any of this still be necessary?

@tmgdejong
Copy link
Contributor Author

I don't really see an advantage in using sales here, as opposed to making e.g. a MerchandiseSale payable model. If we had a way to make miscellaneous payment requests (#3453) would any of this still be necessary?

The first implementation was with a MerchandiseSale payable model, see c708f32 and before. However, as @JobDoesburg mentioned, this way the board can go to thadmin.thalia.nu and use the continuous merchandise sale shift to add a sale, and the rest (payments, external invoices) will be handled by the already existing code.

Miscellaneous payment requests will not solve the problem of needing a general journal document for a merchandise sale to change the merchandise stock in moneybird.

website/merchandise/models.py Outdated Show resolved Hide resolved
website/sales/signals.py Outdated Show resolved Hide resolved
website/sales/signals.py Outdated Show resolved Hide resolved
website/sales/services.py Outdated Show resolved Hide resolved
website/sales/admin/product_admin.py Outdated Show resolved Hide resolved
website/moneybirdsynchronization/services.py Show resolved Hide resolved
website/moneybirdsynchronization/models.py Show resolved Hide resolved
@tmgdejong tmgdejong requested a review from JobDoesburg November 6, 2023 15:44
@JobDoesburg
Copy link
Contributor

Looks good! Some more remarks that might be nice to account for, but are not important:

  • It is possible to change the price of the product list items to a different value than the price of the merchandise item. You can't really prevent that (except with setter and getter behavior specifically overriding this). But you might want to disable editing in the admin, simply by overriding the has_edit_permission and has_add_permission on the inline
  • Might be nice to add a help text specifying which values are incl and excl VAT

@JobDoesburg
Copy link
Contributor

Also, I just realized, we might actually not want to make merchandise items actual sales products (extending the model like is implemented in this PR now). But only add a foreign key between them. Namely, we probably want to keep track of what sizes are sold, while we don't want to list every individual size on the website. So there should be a "t-shirt" in the merchandise app, and "T-shirt size L 22-23" in the sales app (with a foreign key to the merchandise app). That also simplifies the migrations

@DeD1rk
Copy link
Member

DeD1rk commented Nov 6, 2023

I really don't like making sales depend on merchandise. While I haven't really looked into it yet, it does look like the added stuff from services can simply move into merchandise/services.

Regarding different sizes, a FK from product to merchandise item would be a nasty dependency, but how it is now seems fine (although it could just be a FK to product instead of inheritance) but if we want separate sizes IMO that should not use a FK from product (either a through model to emulate that without changing product, or e.g. make separate linked merchandise items and don't display some of them)

@JobDoesburg
Copy link
Contributor

@movieminer @DeD1rk I have pushed one commit that changes the data model a little bit, to fix the things mentioned above. This does need some finishing touches, but I currently don't have the time. Feel free to work on it yourself, otherwise I might do it in the upcoming days

@tmgdejong
Copy link
Contributor Author

I don't think we need to integrate different sizes in the site, since all the different sizes still cost the same, and we don't want to keep track of the sales in concrexit (since we also don't keep track of stock). The board still needs to note the sale in their cash book, and adding the sale to the site is more of a tool to register the sale in moneybird.

@DeD1rk
Copy link
Member

DeD1rk commented Nov 7, 2023

I just moved the changes from sales to merchandise so the dependence is clean. I'll probably take a look at the rest in a few days

@JobDoesburg
Copy link
Contributor

we don't want to keep track of the sales in concrexit (since we also don't keep track of stock). The board still needs to note the sale in their cash book

That's not the idea right? The website becomes the cash book as far as I understand it

@DeD1rk DeD1rk added the feature Issues regarding a complete new feature label Nov 9, 2023
@JobDoesburg JobDoesburg force-pushed the merchandise-sales-moneybird-integration branch from 58e3dd3 to 864f33a Compare November 12, 2023 21:52
@JobDoesburg
Copy link
Contributor

@movieminer could you test if it still works for you? I think it should be ready now

@@ -54,6 +56,8 @@ def date_for_payable_model(obj) -> Union[datetime.datetime, datetime.date]:
return obj.shift.start
if isinstance(obj, (Registration, Renewal)):
return obj.created_at.date()
if isinstance(obj, Order):
Copy link
Member

Choose a reason for hiding this comment

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

This is unreachable: there's already a branch for Order in line 55

@@ -41,6 +41,8 @@ def project_name_for_payable_model(obj) -> Optional[str]:
return f"{obj.shift} [{start_date}]"
if isinstance(obj, (Registration, Renewal)):
return None
if isinstance(obj, Order):
Copy link
Member

Choose a reason for hiding this comment

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

This is unreachable

@@ -64,7 +68,10 @@ def period_for_payable_model(obj) -> Optional[str]:
# Only bill for the start date, ignore the until date.
date = obj.membership.since
return f"{date.strftime('%Y%m%d')}..{date.strftime('%Y%m%d')}"
return None
if isinstance(obj, Order):
Copy link
Member

Choose a reason for hiding this comment

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

This would be incorrect for normal sales orders

if isinstance(obj, Order):
return settings.MONEYBIRD_MERCHANDISE_SALES_LEDGER_ID

raise ValueError(f"Unknown payable model {obj}")
Copy link
Member

Choose a reason for hiding this comment

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

I think it should just return none for the payables right?

@JobDoesburg
Copy link
Contributor

I just realized we actually had to sync things even differently

@ColonelPhantom
Copy link
Contributor

This seems pretty stale. Do we still want to do anything with this?

@T8902
Copy link
Contributor

T8902 commented Nov 6, 2024

@tmgdejong Im going to close this due to no activity

@T8902 T8902 closed this Nov 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Issues regarding a complete new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Merchandise products in sales productlists
5 participants