From df00f0179eeed20acafe41bc1207a5174c9feba3 Mon Sep 17 00:00:00 2001 From: Jan Baykara Date: Mon, 9 May 2022 02:56:46 +0100 Subject: [PATCH 1/4] Add Mailchimp contact importing --- app/settings/base.py | 5 ++++ app/signals.py | 9 +++++++ app/utils/mailchimp.py | 58 ++++++++++++++++++++++++++++++++++++++++++ app/views.py | 6 +++++ poetry.lock | 24 ++++++++++++++--- pyproject.toml | 1 + 6 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 app/utils/mailchimp.py diff --git a/app/settings/base.py b/app/settings/base.py index f79f22b4..01d7be91 100644 --- a/app/settings/base.py +++ b/app/settings/base.py @@ -318,3 +318,8 @@ # Facebook FACEBOOK_PIXEL = os.getenv("FACEBOOK_PIXEL", None) + +# Mailchimp +MAILCHIMP_API_KEY = os.getenv("MAILCHIMP_API_KEY", None) +MAILCHIMP_SERVER_PREFIX = os.getenv("MAILCHIMP_SERVER_PREFIX", "us12") +MAILCHIMP_LIST_ID = os.getenv("MAILCHIMP_LIST_ID", "327021") diff --git a/app/signals.py b/app/signals.py index a8d24230..25451381 100644 --- a/app/signals.py +++ b/app/signals.py @@ -8,6 +8,7 @@ from app import analytics from app.models.wagtail import BookPage +from app.utils.mailchimp import tag_user_in_mailchimp from app.utils.stripe import gift_recipient_subscription_from_code @@ -27,6 +28,9 @@ def cancel_gift_recipient_subscription(event, **kwargs): customer = Customer.objects.filter(id=object.get("customer")).first() if customer is not None and customer.subscriber is not None: analytics.cancel_gift_card(customer.subscriber) + tag_user_in_mailchimp( + customer.subscriber, tags_to_enable=["CANCELLED_GIFT_GIVER"] + ) except Exception as e: capture_exception(e) pass @@ -36,6 +40,11 @@ def cancel_gift_recipient_subscription(event, **kwargs): customer = Customer.objects.filter(id=object.get("customer")).first() if customer is not None and customer.subscriber is not None: analytics.cancel_membership(customer.subscriber) + tag_user_in_mailchimp( + customer.subscriber, + tags_to_enable=["CANCELLED"], + tags_to_disable=["MEMBER"], + ) except Exception as e: capture_exception(e) pass diff --git a/app/utils/mailchimp.py b/app/utils/mailchimp.py new file mode 100644 index 00000000..13330090 --- /dev/null +++ b/app/utils/mailchimp.py @@ -0,0 +1,58 @@ +import hashlib + +import mailchimp_marketing as MailchimpMarketing +from django.conf import settings +from mailchimp_marketing.api_client import ( + MailchimpApiClientError as MailchimpApiClientError, +) + +from app.models import User + +mailchimp = MailchimpMarketing.Client() +MAILCHIMP_IS_ACTIVE = ( + settings.MAILCHIMP_API_KEY is not None + and settings.MAILCHIMP_SERVER_PREFIX is not None + and settings.MAILCHIMP_LIST_ID is not None +) +if MAILCHIMP_IS_ACTIVE: + mailchimp.set_config(settings.MAILCHIMP_API_KEY, settings.MAILCHIMP_SERVER_PREFIX) + + +def email_to_hash(email): + return hashlib.md5(email.encode("utf-8").lower()).hexdigest() + + +def mailchimp_contact_for_user(user: User): + if not MAILCHIMP_IS_ACTIVE: + return False + return mailchimp.lists.set_list_member( + settings.MAILCHIMP_LIST_ID, + email_to_hash(user.primary_email), + { + "email_address": user.primary_email, + "merge_fields": {"FNAME": user.first_name, "LNAME": user.last_name}, + "status_if_new": "subscribed" + if user.gdpr_email_consent + else "unsubscribed", + }, + ) + + +def tag_user_in_mailchimp(user: User, tags_to_enable=list(), tags_to_disable=list()): + if not MAILCHIMP_IS_ACTIVE: + return + contact = mailchimp_contact_for_user(user) + if contact is None: + return + try: + response = mailchimp.lists.update_list_member_tags( + settings.MAILCHIMP_LIST_ID, + email_to_hash(user.primary_email), + { + "tags": [{"name": tag, "status": "active"} for tag in tags_to_enable] + + [{"name": tag, "status": "inactive"} for tag in tags_to_disable] + }, + ) + print(f"client.lists.update_list_member_tags() response: {response}") + except MailchimpApiClientError as error: + print(f"An exception occurred: {error.text}") diff --git a/app/views.py b/app/views.py index 2e55804f..2763412b 100644 --- a/app/views.py +++ b/app/views.py @@ -30,6 +30,7 @@ from app.models import LBCProduct from app.models.stripe import ShippingZone from app.models.wagtail import MembershipPlanPrice +from app.utils.mailchimp import tag_user_in_mailchimp from app.utils.stripe import ( configure_gift_giver_subscription_and_code, create_gift_recipient_subscription, @@ -162,12 +163,14 @@ def get_context_data(self, **kwargs): """ self.finish_gift_purchase(session, subscription, customer) analytics.buy_gift(self.request.user) + tag_user_in_mailchimp(self.request.user, tags_to_enable=["GIFT_GIVER"]) elif session is not None and subscription is not None and customer is not None: """ Resolve a normal membership purchase """ self.finish_self_purchase(session, subscription, customer) analytics.buy_membership(self.request.user) + tag_user_in_mailchimp(self.request.user, tags_to_enable=["MEMBER"]) analytics.signup(self.request.user) @@ -364,6 +367,9 @@ def form_valid(self, form): djstripe.models.Customer.sync_from_stripe_data(customer) analytics.redeem(self.request.user) + tag_user_in_mailchimp( + self.request.user, tags_to_enable=["MEMBER", "GIFT_RECIPIENT"] + ) return super().form_valid(form) diff --git a/poetry.lock b/poetry.lock index 8a5d2b83..82023ca6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -558,7 +558,7 @@ test = ["pytest (>=3.1.0)", "pytest-django", "pytest-pythonpath", "pytest-cov", [[package]] name = "django-shopify-webhook" -version = "0.5.1" +version = "0.6.0" description = "A package for the creation of Shopify Apps using the Embedded App SDK." category = "main" optional = false @@ -572,7 +572,7 @@ django = ">=2.2" type = "git" url = "https://github.com/discolabs/django-shopify-webhook.git" reference = "master" -resolved_reference = "9e875dac38c5c5389c6db7ce6efa0ddcc02898cc" +resolved_reference = "a0ba36119455faf99072f668238d2a9e90e06410" [[package]] name = "django-storages" @@ -857,6 +857,21 @@ category = "dev" optional = false python-versions = ">=3.6" +[[package]] +name = "mailchimp-marketing" +version = "3.0.75" +description = "Mailchimp Marketing API" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +certifi = ">=2017.4.17" +python-dateutil = ">=2.1" +requests = ">=2.23" +six = ">=1.10" +urllib3 = ">=1.23" + [[package]] name = "markuppy" version = "1.14" @@ -1732,7 +1747,7 @@ python-versions = "*" [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "640190fbbf2b9f521234fc241108edbf0677a69c55ec9662546e6a4e05b09422" +content-hash = "939aa9ce8e6bb4aa3828c1292a38a545ab47a47392d5494aed6e1c5d4f11fc1f" [metadata.files] anyascii = [ @@ -2141,6 +2156,9 @@ lazy-object-proxy = [ {file = "lazy_object_proxy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61"}, {file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"}, ] +mailchimp-marketing = [ + {file = "mailchimp_marketing-3.0.75-py3-none-any.whl", hash = "sha256:34ca29268823504ddc873b29724905bab7f8eeb42ddb53f66077a2224cd3f02f"}, +] markuppy = [ {file = "MarkupPy-1.14.tar.gz", hash = "sha256:1adee2c0a542af378fe84548ff6f6b0168f3cb7f426b46961038a2bcfaad0d5f"}, ] diff --git a/pyproject.toml b/pyproject.toml index ae0d8d9f..1d6096b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,6 +55,7 @@ dj-stripe = {git = "https://github.com/commonknowledge/dj-stripe.git", rev = "fi django-shopify-webhook = {git = "https://github.com/discolabs/django-shopify-webhook.git"} posthog = "^1.4.7" sentry-sdk = "^1.5.11" +mailchimp-marketing = "^3.0.75" [tool.poetry.dev-dependencies] bandit = "^1.7.0" From be4e134c129a3f44b8ffb30949ab78fbdf5629af Mon Sep 17 00:00:00 2001 From: Jan Baykara Date: Mon, 9 May 2022 03:18:38 +0100 Subject: [PATCH 2/4] Generate Shopify orders for signups and so on --- app/models/django.py | 12 ++- app/templates/app/confirm_shipping.html | 2 +- .../app/includes/membership_card.html | 6 +- app/templates/app/redeem.html | 2 +- app/utils/shopify.py | 80 +++++++++++++++++++ app/utils/stripe.py | 2 + app/views.py | 38 +++++++++ app/wagtail_hooks.py | 31 ------- 8 files changed, 136 insertions(+), 37 deletions(-) diff --git a/app/models/django.py b/app/models/django.py index 4c4c04d8..f5fe241c 100644 --- a/app/models/django.py +++ b/app/models/django.py @@ -93,7 +93,7 @@ def subscription_status(self): return None @property - def subscribed_product(self) -> LBCProduct: + def primary_product(self) -> LBCProduct: try: if self.active_subscription is not None: product = get_primary_product_for_djstripe_subscription( @@ -119,6 +119,16 @@ def gifts_bought(self): .order_by("-created") ) + @property + def gift_giver(self): + try: + gift_giver_subscription = self.active_subscription.gift_giver_subscription + sub = djstripe.models.Subscription.objects.get(id=gift_giver_subscription) + user = sub.customer.subscriber + return user + except: + return None + def __str__(self) -> str: fn = self.get_full_name() if fn is not None and len(fn): diff --git a/app/templates/app/confirm_shipping.html b/app/templates/app/confirm_shipping.html index 5b092c23..ce49c0ca 100644 --- a/app/templates/app/confirm_shipping.html +++ b/app/templates/app/confirm_shipping.html @@ -45,7 +45,7 @@

Confirm{% if gift_mode %} gift{% endif %} d
diff --git a/app/templates/app/includes/membership_card.html b/app/templates/app/includes/membership_card.html index f7782be4..48a9a5ae 100644 --- a/app/templates/app/includes/membership_card.html +++ b/app/templates/app/includes/membership_card.html @@ -8,10 +8,10 @@
Membership No. #{{ user.stripe_customer.invoice_prefix }}
-
{{ user.subscribed_product.name}}
+
{{ user.primary_product.name}}
{% comment %}
{{user.subscribed_price.human_readable_price}}
{% endcomment %} - {% if user.subscribed_product.gift_giver_subscription %} -
Gifted by {{user.subscribed_product.gift_giver_subscription.customer.subscriber}}
+ {% if user.primary_product.gift_giver_subscription %} +
Gifted by {{user.gift_giver}}
{% endif %}
Since {{ user.active_subscription.created|date:"d M Y" }}
{% if user.active_subscription.cancel_at %} diff --git a/app/templates/app/redeem.html b/app/templates/app/redeem.html index 5969355d..3a055d24 100644 --- a/app/templates/app/redeem.html +++ b/app/templates/app/redeem.html @@ -38,7 +38,7 @@

Someone bought you a gift!

diff --git a/app/utils/shopify.py b/app/utils/shopify.py index 3827efe8..77403a87 100644 --- a/app/utils/shopify.py +++ b/app/utils/shopify.py @@ -1,5 +1,6 @@ import json +import pycountry import shopify from dateutil.parser import parse from django.conf import settings @@ -39,3 +40,82 @@ def parse_metafield(f): return json.loads(f.value) else: return f.value + + +def convert_stripe_address_to_shopify(user): + shipping = user.stripe_customer.shipping + return { + "first_name": user.first_name, + "last_name": user.last_name, + "address1": shipping.get("address").get("line1"), + "address2": shipping.get("address").get("line2"), + "city": shipping.get("address").get("city"), + "country": pycountry.countries.search_fuzzy( + shipping.get("address").get("country") + )[0].name, + "zip": shipping.get("address").get("postal_code"), + "country_code": shipping.get("address").get("country"), + } + + +def to_shopify_address(user): + if ( + user.stripe_customer + and user.stripe_customer.shipping is not None + and len(user.stripe_customer.shipping.keys()) > 0 + ): + return convert_stripe_address_to_shopify(user) + return None + + +def create_shopify_order(user, line_items=list(), email=False, tags=list()): + o = shopify.Order() + o.line_items = line_items + # [ + # { + # # "variant_id": variant_id, + # "title": "New Signup", + # "price": 0, + # "requiresShipping": True, + # "quantity": quantity, + # } + # ] + o.financial_status = "paid" + + # Shopify customer link + # if user.shopify_customer_id is None: + # cs = shopify.Customer.search(email=o.email) + # if len(cs) > 0: + # user.shopify_customer_id = cs[0].id + # user.save() + # else: + # c = shopify.Customer() + # c.first_name = "andres" + # c.last_name = "cepeda" + # if to_shopify_address(user) is not None: + # c.addresses = [to_shopify_address(user)] + # c.default_address = to_shopify_address(user) + # c.save() + # user.shopify_customer_id = c.id + # user.save() + # if user.shopify_customer_id is None: + # raise ValueError("Couldn't create shipping order, because customer couldn't be identified") + + # o.customer = { "id": user.shopify_customer_id } + if not email: + o.send_receipt = False + o.send_fulfillment_receipt = False + else: + o.email = user.primary_email + + if to_shopify_address(user) is not None: + o.shipping_address = to_shopify_address(user) + o.tags = tags + + if not settings.STRIPE_LIVE_MODE: + tags += ["TEST"] + + o.save() + + if not settings.STRIPE_LIVE_MODE: + o.cancel() diff --git a/app/utils/stripe.py b/app/utils/stripe.py index b454a325..57a7b9a2 100644 --- a/app/utils/stripe.py +++ b/app/utils/stripe.py @@ -245,6 +245,7 @@ def create_gift_recipient_subscription( si.price, zone ), "quantity": si.quantity, + "metadata": {"primary": True}, } ) else: @@ -257,6 +258,7 @@ def create_gift_recipient_subscription( # Membership "price_data": recreate_one_off_stripe_price(si.price), "quantity": si.quantity, + "metadata": {"shipping": True}, } ) diff --git a/app/views.py b/app/views.py index 2763412b..7c125106 100644 --- a/app/views.py +++ b/app/views.py @@ -31,6 +31,7 @@ from app.models.stripe import ShippingZone from app.models.wagtail import MembershipPlanPrice from app.utils.mailchimp import tag_user_in_mailchimp +from app.utils.shopify import create_shopify_order from app.utils.stripe import ( configure_gift_giver_subscription_and_code, create_gift_recipient_subscription, @@ -164,6 +165,19 @@ def get_context_data(self, **kwargs): self.finish_gift_purchase(session, subscription, customer) analytics.buy_gift(self.request.user) tag_user_in_mailchimp(self.request.user, tags_to_enable=["GIFT_GIVER"]) + prod_id = subscription.metadata.get("primary_product") + prod = djstripe.models.Product.objects.get(id=prod_id) + create_shopify_order( + self.request.user, + line_items=[ + { + "title": f"Gift Card Purchase - {prod.name}", + "quantity": 1, + "price": 0, + } + ], + tags=["Gift Card Purchase"], + ) elif session is not None and subscription is not None and customer is not None: """ Resolve a normal membership purchase @@ -171,6 +185,19 @@ def get_context_data(self, **kwargs): self.finish_self_purchase(session, subscription, customer) analytics.buy_membership(self.request.user) tag_user_in_mailchimp(self.request.user, tags_to_enable=["MEMBER"]) + prod_id = subscription.metadata.get("primary_product") + prod = djstripe.models.Product.objects.get(id=prod_id) + create_shopify_order( + self.request.user, + line_items=[ + { + "title": f"Membership Subscription Purchase — {prod.name}", + "quantity": 1, + "price": 0, + } + ], + tags=["Membership Subscription Purchase"], + ) analytics.signup(self.request.user) @@ -370,6 +397,17 @@ def form_valid(self, form): tag_user_in_mailchimp( self.request.user, tags_to_enable=["MEMBER", "GIFT_RECIPIENT"] ) + create_shopify_order( + self.request.user, + line_items=[ + { + "title": f"Gift Card Redeemed — {self.request.user.primary_product.name}", + "quantity": 1, + "price": 0, + } + ], + tags=["Membership Subscription Purchase", "Gift Card Redeemed"], + ) return super().form_valid(form) diff --git a/app/wagtail_hooks.py b/app/wagtail_hooks.py index 623e9c2d..288944f5 100644 --- a/app/wagtail_hooks.py +++ b/app/wagtail_hooks.py @@ -141,34 +141,3 @@ def get_queryset(self, request): # Now you just need to register your customised ModelAdmin class with Wagtail modeladmin_register(CustomerAdmin) - - -def create_shopify_order(self, user, quantity=1, tags=["Membership Shipment"]): - o = shopify.Order() - o.line_items = [ - { - # "variant_id": variant_id, - "title": "New Signup", - "requiresShipping": True, - "quantity": quantity, - } - ] - o.financial_status = "paid" - o.email = user.primary_email - c = shopify.Customer.search(email=o.email) - shopify.Customer.create(email=o.email) - o.customer = {"id": c[0].id} - o.send_receipt = False - o.send_fulfillment_receipt = False - # TODO: convert Shipping address from Stripe to Shopify format - o.shipping_address = { - "address1": "1 Byers Road", - "address2": "Flat 4/2", - "city": "Glasgow", - "country": "United Kingdom", - "zip": "G115RD", - "name": "Jan Baykara", - "country_code": "GB", - } - o.tags = tags - return o From 31570c38fb9949131688b7f29abc8a56be296425 Mon Sep 17 00:00:00 2001 From: Jan Baykara Date: Mon, 9 May 2022 04:19:18 +0100 Subject: [PATCH 3/4] Fixes --- app/models/wagtail.py | 4 +- app/templates/app/frames/shipping_cost.html | 4 + app/utils/mailchimp.py | 13 +-- app/utils/shopify.py | 118 +++++++++++--------- app/utils/stripe.py | 9 +- app/views.py | 8 +- 6 files changed, 85 insertions(+), 71 deletions(-) diff --git a/app/models/wagtail.py b/app/models/wagtail.py index 7f576b3e..96462b92 100644 --- a/app/models/wagtail.py +++ b/app/models/wagtail.py @@ -249,7 +249,7 @@ def to_price_data(self, product): "interval": self.interval, "interval_count": self.interval_count, }, - "metadata": self.metadata, + "metadata": {**(self.metadata or {}), "primary": True}, } def to_shipping_price_data(self, zone): @@ -282,14 +282,12 @@ def to_checkout_line_items(self, zone=None, product=None): { "price_data": self.to_price_data(product), "quantity": 1, - "metadata": {"primary": True}, }, # Keep the shipping fee in, even if it's 0 # so that we can upgrade/downgrade shipping prices in the future { "price_data": self.to_shipping_price_data(zone), "quantity": 1, - "metadata": {"shipping": True}, }, ] return line_items diff --git a/app/templates/app/frames/shipping_cost.html b/app/templates/app/frames/shipping_cost.html index 41a511c1..eb183697 100644 --- a/app/templates/app/frames/shipping_cost.html +++ b/app/templates/app/frames/shipping_cost.html @@ -30,6 +30,10 @@ {% money_localize final_price %}{{ price.humanised_interval }}
+ {% if request.GET.gift_mode %} +

On the next page, please add your own shipping address, in case we need to send you any gift card materials.

+

Your gift recipient will be able to enter their own address when they redeem.

+ {% endif %} {% bootstrap_button button_type="submit" content="Continue to payment" button_class='w-100 btn-primary my-2' %} {% endif %} diff --git a/app/utils/mailchimp.py b/app/utils/mailchimp.py index 13330090..c08bc09d 100644 --- a/app/utils/mailchimp.py +++ b/app/utils/mailchimp.py @@ -2,9 +2,7 @@ import mailchimp_marketing as MailchimpMarketing from django.conf import settings -from mailchimp_marketing.api_client import ( - MailchimpApiClientError as MailchimpApiClientError, -) +from mailchimp_marketing.api_client import ApiClientError as MailchimpApiClientError from app.models import User @@ -39,7 +37,11 @@ def mailchimp_contact_for_user(user: User): def tag_user_in_mailchimp(user: User, tags_to_enable=list(), tags_to_disable=list()): + tags = [{"name": tag, "status": "active"} for tag in tags_to_enable] + [ + {"name": tag, "status": "inactive"} for tag in tags_to_disable + ] if not MAILCHIMP_IS_ACTIVE: + print("tag_user_in_mailchimp", tags) return contact = mailchimp_contact_for_user(user) if contact is None: @@ -48,10 +50,7 @@ def tag_user_in_mailchimp(user: User, tags_to_enable=list(), tags_to_disable=lis response = mailchimp.lists.update_list_member_tags( settings.MAILCHIMP_LIST_ID, email_to_hash(user.primary_email), - { - "tags": [{"name": tag, "status": "active"} for tag in tags_to_enable] - + [{"name": tag, "status": "inactive"} for tag in tags_to_disable] - }, + {"tags": tags}, ) print(f"client.lists.update_list_member_tags() response: {response}") except MailchimpApiClientError as error: diff --git a/app/utils/shopify.py b/app/utils/shopify.py index 77403a87..40a40e6f 100644 --- a/app/utils/shopify.py +++ b/app/utils/shopify.py @@ -44,7 +44,7 @@ def parse_metafield(f): def convert_stripe_address_to_shopify(user): shipping = user.stripe_customer.shipping - return { + address = { "first_name": user.first_name, "last_name": user.last_name, "address1": shipping.get("address").get("line1"), @@ -57,65 +57,79 @@ def convert_stripe_address_to_shopify(user): "country_code": shipping.get("address").get("country"), } + ret = {} + for k in address: + if address.get(k, None) is not None and address.get(k, "") != "": + ret[k] = address[k] + + if len(ret.keys()) == 0: + return None + + return ret + def to_shopify_address(user): if ( user.stripe_customer and user.stripe_customer.shipping is not None - and len(user.stripe_customer.shipping.keys()) > 0 + and user.stripe_customer.shipping.get("address", {}).get("line1", False) ): return convert_stripe_address_to_shopify(user) return None def create_shopify_order(user, line_items=list(), email=False, tags=list()): - o = shopify.Order() - o.line_items = line_items - # [ - # { - # # "variant_id": variant_id, - # "title": "New Signup", - # "price": 0, - # "requiresShipping": True, - # "quantity": quantity, - # } - # ] - o.financial_status = "paid" - - # Shopify customer link - # if user.shopify_customer_id is None: - # cs = shopify.Customer.search(email=o.email) - # if len(cs) > 0: - # user.shopify_customer_id = cs[0].id - # user.save() - # else: - # c = shopify.Customer() - # c.first_name = "andres" - # c.last_name = "cepeda" - # if to_shopify_address(user) is not None: - # c.addresses = [to_shopify_address(user)] - # c.default_address = to_shopify_address(user) - # c.save() - # user.shopify_customer_id = c.id - # user.save() - # if user.shopify_customer_id is None: - # raise ValueError("Couldn't create shipping order, because customer couldn't be identified") - - # o.customer = { "id": user.shopify_customer_id } - if not email: - o.send_receipt = False - o.send_fulfillment_receipt = False - else: - o.email = user.primary_email - - if to_shopify_address(user) is not None: - o.shipping_address = to_shopify_address(user) - o.tags = tags - - if not settings.STRIPE_LIVE_MODE: - tags += ["TEST"] - - o.save() - - if not settings.STRIPE_LIVE_MODE: - o.cancel() + if not settings.SHOPIFY_DOMAIN or settings.SHOPIFY_PRIVATE_APP_PASSWORD: + with shopify.Session.temp( + settings.SHOPIFY_DOMAIN, "2021-10", settings.SHOPIFY_PRIVATE_APP_PASSWORD + ): + o = shopify.Order() + o.line_items = line_items + # [ + # { + # # "variant_id": variant_id, + # "title": "New Signup", + # "price": 0, + # "requiresShipping": True, + # "quantity": quantity, + # } + # ] + o.financial_status = "paid" + + # Shopify customer link + # if user.shopify_customer_id is None: + # cs = shopify.Customer.search(email=o.email) + # if len(cs) > 0: + # user.shopify_customer_id = cs[0].id + # user.save() + # else: + # c = shopify.Customer() + # c.first_name = "andres" + # c.last_name = "cepeda" + # if to_shopify_address(user) is not None: + # c.addresses = [to_shopify_address(user)] + # c.default_address = to_shopify_address(user) + # c.save() + # user.shopify_customer_id = c.id + # user.save() + # if user.shopify_customer_id is None: + # raise ValueError("Couldn't create shipping order, because customer couldn't be identified") + + # o.customer = { "id": user.shopify_customer_id } + if not email: + o.send_receipt = False + o.send_fulfillment_receipt = False + o.note = f"For {user} / {user.primary_email}. Email not attached to order to prevent Shopify email notifications going out." + else: + o.email = user.primary_email + + o.shipping_address = to_shopify_address(user) + o.tags = tags + + if not settings.STRIPE_LIVE_MODE: + tags += ["TEST"] + + o.save() + + if not settings.STRIPE_LIVE_MODE: + o.cancel() diff --git a/app/utils/stripe.py b/app/utils/stripe.py index 57a7b9a2..e97e00ed 100644 --- a/app/utils/stripe.py +++ b/app/utils/stripe.py @@ -134,7 +134,7 @@ def get_gift_card_coupon(product: djstripe.models.Product) -> djstripe.models.Co return coupon -def recreate_one_off_stripe_price(price: stripe.Price): +def recreate_one_off_stripe_price(price: stripe.Price, **kwargs): return { "unit_amount_decimal": price.unit_amount, "currency": price.currency, @@ -146,6 +146,7 @@ def recreate_one_off_stripe_price(price: stripe.Price): "interval_count", ), ), + **kwargs, } @@ -245,7 +246,6 @@ def create_gift_recipient_subscription( si.price, zone ), "quantity": si.quantity, - "metadata": {"primary": True}, } ) else: @@ -256,9 +256,10 @@ def create_gift_recipient_subscription( items.append( { # Membership - "price_data": recreate_one_off_stripe_price(si.price), + "price_data": recreate_one_off_stripe_price( + si.price, metadata={"primary": True} + ), "quantity": si.quantity, - "metadata": {"shipping": True}, } ) diff --git a/app/views.py b/app/views.py index 7c125106..5d0588e1 100644 --- a/app/views.py +++ b/app/views.py @@ -165,7 +165,7 @@ def get_context_data(self, **kwargs): self.finish_gift_purchase(session, subscription, customer) analytics.buy_gift(self.request.user) tag_user_in_mailchimp(self.request.user, tags_to_enable=["GIFT_GIVER"]) - prod_id = subscription.metadata.get("primary_product") + prod_id = session.metadata.get("primary_product") prod = djstripe.models.Product.objects.get(id=prod_id) create_shopify_order( self.request.user, @@ -185,7 +185,7 @@ def get_context_data(self, **kwargs): self.finish_self_purchase(session, subscription, customer) analytics.buy_membership(self.request.user) tag_user_in_mailchimp(self.request.user, tags_to_enable=["MEMBER"]) - prod_id = subscription.metadata.get("primary_product") + prod_id = session.metadata.get("primary_product", None) prod = djstripe.models.Product.objects.get(id=prod_id) create_shopify_order( self.request.user, @@ -566,6 +566,7 @@ def create_checkout_context( "address": "auto", "name": "auto", }, + shipping_address_collection={"allowed_countries": zone.country_codes}, metadata={"primary_product": product.id}, ) @@ -574,9 +575,6 @@ def create_checkout_context( checkout_args["metadata"]["gift_mode"] = True next = reverse_lazy("completed_gift_purchase") else: - checkout_args["shipping_address_collection"] = { - "allowed_countries": zone.country_codes - } next = reverse_lazy("completed_membership_purchase") return {"checkout_args": checkout_args, "next": next} From 91989fecad9300806b12c51b342b4e3d4014490e Mon Sep 17 00:00:00 2001 From: Jan Baykara Date: Mon, 9 May 2022 04:22:57 +0100 Subject: [PATCH 4/4] Improve Shopify order note --- app/utils/shopify.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/utils/shopify.py b/app/utils/shopify.py index 40a40e6f..4b17343d 100644 --- a/app/utils/shopify.py +++ b/app/utils/shopify.py @@ -119,7 +119,7 @@ def create_shopify_order(user, line_items=list(), email=False, tags=list()): if not email: o.send_receipt = False o.send_fulfillment_receipt = False - o.note = f"For {user} / {user.primary_email}. Email not attached to order to prevent Shopify email notifications going out." + o.note = f"Email: {user.primary_email}. Stripe customer: {user.stripe_customer.id}." else: o.email = user.primary_email