Skip to content

Commit 9a61afe

Browse files
committed
Merge remote-tracking branch 'origin/master' into emaus/swish
2 parents c2e1c2b + 30d9b21 commit 9a61afe

File tree

5 files changed

+104
-35
lines changed

5 files changed

+104
-35
lines changed

.github/workflows/check-formatting.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@ name: Check formatting of source code
22

33
on:
44
push:
5-
branches:
6-
- "**"
5+
branches: [master, main]
76
pull_request:
8-
branches:
9-
- "**"
7+
types: [synchronize, opened]
108

119
jobs:
1210
ruff:

.github/workflows/makeradmin.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ name: Build and run tests for makeradmin
22

33
on:
44
push:
5-
branches:
6-
- "**"
5+
branches: [master, main]
6+
pull_request:
7+
types: [synchronize, opened]
78

89
jobs:
910
test:

README.md

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ These are important to make sure links work, but also to handle CORS in the brow
120120
### System tests/integration tests that requires a running installation
121121

122122
Systests are written in python and the sources for the systests are in the api/src/systest directory (because it shares a lot of code with the api unittests). There are
123-
tests using the api as well as selenium tests. Those tests are also run in travis.
123+
tests using the api as well as selenium tests. Those tests are also run in Github actions.
124124

125125
You can run the tests in test containers using a one off db with:
126126

@@ -154,7 +154,7 @@ If you for some reason want to remove the existing database and start from scrat
154154
make clean-nuke
155155
```
156156

157-
_Warning: this will completely wipe out all your makeradmin data!_
157+
⚠️ _Warning: this will completely wipe out all your makeradmin data!_
158158

159159
After this you can run `make firstrun` again to set things up again.
160160

@@ -184,36 +184,18 @@ These subscriptions will automatically be turned into makeradmin products so tha
184184

185185
Note: You should _not_ modify these products in makeradmin. They will be reset whenever the docker container restarts anyway (when the registration page is visited).
186186

187-
#### Needed Stripe configuration
187+
#### Required Stripe configuration
188188

189-
The configuration needed on stripe is:
190-
191-
- Create a **product** for base membership. Add the metadata "subscription_type"="membership" to the **product** item
192-
- Add a yearly **price**, and add the metadata "price_type"="recurring" to the **price** item
193-
- Create a **product** for makerspace access. Add the metadata "subscription_type"="labaccess" to the **product** item
194-
- Add a monthly price, and add the metadata "price_type"="recurring" to the **price** item
195-
- Add a **price** for N months, where N is the binding period as specified in `stripe_subscriptions.py->BINDING_PERIOD`. The price should be N times the recurring price. Add the metadata "price_type"="binding_period"
196-
- Create a **coupon** for low income discount. It should be with percentage discount. Add the metadata "makerspace_price_level" = "low_income_discount"
197-
198-
You can achieve all of this using the Stripe CLI:
189+
Run the following script to create the required Stripe products. _You should only run it once._ But if anything goes wrong, you can modify the products from the Stripe dashboard.
199190

200191
```bash
201-
# Create a yearly membership product with a price
202-
stripe products create -d 'metadata[subscription_type]=membership' --name='Base membership'
203-
# -> This gives a product ID `prod_MEMBERSHIP` that you need to substitute below
204-
stripe prices create --unit-amount=20000 --currency=sek -d "recurring[interval]"=year --product="prod_MEMBERSHIP" -d "recurring[interval_count]"=1 -d 'metadata[price_type]=recurring'
205-
206-
# Create a makerspace access product with prices
207-
stripe products create -d 'metadata[subscription_type]=labaccess' --name='Makerspace access'
208-
# -> This gives a product ID `prod_LABACCESS` that you need to substitute below
209-
stripe prices create --unit-amount=30000 --currency=sek -d "recurring[interval]"=month --product="prod_LABACCESS" -d "recurring[interval_count]"=1 -d 'metadata[price_type]=recurring'
210-
stripe prices create --unit-amount=60000 --currency=sek -d "recurring[interval]"=month --product="prod_LABACCESS" -d "recurring[interval_count]"=2 -d 'metadata[price_type]=binding_period'
211-
212-
# Create a coupon
213-
stripe coupons create --name='Low income discount' --percent-off=50 -d 'metadata[makerspace_price_level]=low_income_discount'
192+
# Print the help
193+
./create_stripe_products.py --help
194+
# Example usage (change the arguments to suit your needs)
195+
./create_stripe_products.py --yearly-price 200 --monthly-price 300 --binding-period 2
214196
```
215197

216-
If you try to access any page which needs these products (e.g. the registration page, or the member page), makeradmin will fetch them from stripe and do a bunch of validation checks.
198+
If you try to access any page which needs these products (e.g. the registration page, or the member page), makeradmin will fetch them from stripe and do a bunch of validation checks on them.
217199

218200
### Setting up required products in makeradmin
219201

api/src/shop/stripe_payment_intent.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,8 @@ def pay_with_stripe(transaction: Transaction, payment_method_id: str, setup_futu
206206
def get_stripe_payment_intents(start_date: datetime, end_date: datetime) -> List[stripe.PaymentIntent]:
207207
expand = ["data.latest_charge.balance_transaction"]
208208
created = {
209-
"gte": int(mktime(start_date.astimezone(pytz.UTC).timetuple())),
210-
"lt": int(mktime(end_date.astimezone(pytz.UTC).timetuple())),
209+
"gte": int(start_date.astimezone(pytz.UTC).timestamp()),
210+
"lt": int(end_date.astimezone(pytz.UTC).timestamp()),
211211
}
212212
logger.info(f"Fetching stripe payment intents from {start_date} ({created['gte']}) to {end_date} ({created['lt']})")
213213

create_stripe_products.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#!/usr/bin/env python3
2+
from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser
3+
4+
import stripe
5+
from dotenv import dotenv_values
6+
7+
env = dotenv_values()
8+
stripe.api_key = env.get("STRIPE_PRIVATE_KEY")
9+
currency = env.get("CURRENCY")
10+
11+
12+
def to_stripe_currency(price: float) -> int:
13+
return int(price * 100)
14+
15+
16+
parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
17+
parser.add_argument(
18+
"--yearly-price",
19+
metavar="PRICE",
20+
default=200,
21+
type=float,
22+
help="The price for base membership. Paid each year",
23+
)
24+
parser.add_argument(
25+
"--monthly-price",
26+
metavar="PRICE",
27+
default=300,
28+
type=float,
29+
help="The price for Makerspace access. Paid each month",
30+
)
31+
parser.add_argument(
32+
"--binding-period",
33+
metavar="MONTHS",
34+
default=2,
35+
type=int,
36+
help="The binding period in months.",
37+
)
38+
args = parser.parse_args()
39+
40+
41+
yearly_price = args.yearly_price
42+
monthly_price = args.monthly_price
43+
binding_period_in_months = args.binding_period
44+
45+
exit(0)
46+
47+
48+
base_membership = stripe.Product.create(
49+
name="Base membership",
50+
description="The base membership to the association",
51+
metadata={"subscription_type": "membership"},
52+
)
53+
54+
price_yearly = stripe.Price.create(
55+
unit_amount=to_stripe_currency(yearly_price),
56+
currency=currency,
57+
recurring={"interval": "year", "interval_count": 1},
58+
product=base_membership["id"],
59+
metadata={"price_type": "recurring"},
60+
)
61+
62+
makerspace_access = stripe.Product.create(
63+
name="Makerspace access",
64+
description="The base membership to the association",
65+
metadata={"subscription_type": "labaccess"},
66+
)
67+
68+
price_subscription = stripe.Price.create(
69+
unit_amount=to_stripe_currency(monthly_price),
70+
currency=currency,
71+
recurring={"interval": "month", "interval_count": 1},
72+
product=makerspace_access["id"],
73+
metadata={"price_type": "recurring"},
74+
)
75+
76+
price_binding_period = stripe.Price.create(
77+
unit_amount=to_stripe_currency(monthly_price * binding_period_in_months),
78+
currency=currency,
79+
recurring={"interval": "month", "interval_count": binding_period_in_months},
80+
product=makerspace_access["id"],
81+
metadata={"price_type": "binding_period"},
82+
)
83+
84+
print(f"Base membership ID: {base_membership.id}")
85+
print(f"- price ID: {price_yearly.id}")
86+
print(f"Makerspace access ID: {makerspace_access.id}")
87+
print(f"- subscription price ID: {price_subscription.id}")
88+
print(f"- binding period price ID: {price_binding_period.id}")

0 commit comments

Comments
 (0)