def build_onetime_request_body(donation): """Method to create body with CAPTURE intent""" # returl_url or cancel_url params in application_context tested to be only useful if order not initiated by Javascript APK return \ { "intent": "CAPTURE", "application_context": { "brand_name": get_site_name(), "landing_page": "NO_PREFERENCE", "shipping_preference": "NO_SHIPPING", "user_action": "PAY_NOW", "return_url": reverse_with_site_url('donations:return-from-paypal'), "cancel_url": reverse_with_site_url('donations:cancel-from-paypal') }, "purchase_units": [ { "description": get_site_name() + str(_(" Onetime Donation")), "custom_id": donation.id, "amount": { "currency_code": donation.currency, "value": str(donation.donation_amount) } } ] }
def get_recurring_cancel_request_admin_text(subscription): return _("""Cancellation to a Recurring Donation is requested\n \n Hi Admins,\n This email is to inform you that a cancellation to a recurring donation has been requested on your website. Please complete the request and manually change the subscription status to Cancelled at the link below:\n %(url)s\n \n Donor: %(name)s\n Recurring donation identifier: %(profile_id)s\n Payment method: %(gateway)s\n Recurring donation amount: %(amount)s\n Recurring Status: %(recurring_status)s\n \n Thank you,\n %(sitename)s""") % { 'url': reverse_with_site_url('donations_subscription_modeladmin_inspect', kwargs={'instance_pk': subscription.id}), 'name': subscription.user.fullname, 'profile_id': subscription.profile_id, 'gateway': subscription.gateway, 'amount': displayRecurringAmountWithCurrency(subscription), 'recurring_status': subscription.recurring_status, 'sitename': get_site_name() }
def get_recurring_cancelled_donor_text(subscription): return _("""DONATION CANCELLED\n \n Dear %(name)s,\n Thanks very much for your recent support.\n Your recurring donation to HKFP has been suspended at your request - no further payments will be processed.\n Sign into our support page(%(siteurl)s) (click "forgot password?" if you have trouble logging in) if you wish to support us again in the future. Please email [email protected] if you have any further enquiries.\n From all of us, thank you for backing our team and helping us keep independent media alive in Hong Kong!\n Details of your recurring donation:\n \n Donor: %(name)s\n Recurring donation identifier: %(profile_id)s\n Payment method: %(gateway)s\n Recurring donation amount: %(amount)s\n Recurring Status: %(recurring_status)s\n \n Thank you,\n %(sitename)s""") % { 'name': subscription.user.fullname, 'siteurl': get_site_url(), 'url': reverse_with_site_url('donations:my-recurring-donations'), 'profile_id': subscription.profile_id, 'gateway': displayGateway(subscription), 'amount': displayRecurringAmountWithCurrency(subscription), 'recurring_status': subscription.recurring_status, 'sitename': get_site_name() }
def get_donation_error_admin_text(donation, error_title, error_description): return _("""A Donation Error has occurred.\n \n Hi Admins,\n This email is to inform you that a donation error has occurred on your website:\n %(url)s\n \n Donation transaction ID: %(order)s\n Donor: %(name)s\n Error title: %(error_title)s\n Error description: %(error_description)s\n \n Thank you,\n %(sitename)s""") % { 'url': reverse_with_site_url('donations_donation_modeladmin_inspect', kwargs={'instance_pk': donation.id}), 'order': donation.transaction_id, 'name': donation.donor_name(), 'error_title': error_title, 'error_description': error_description, 'sitename': get_site_name() }
def get_recurring_resumed_donor_text(subscription): return _("""DONATION RESUMED\n \n Dear %(name)s,\n A big "thank you" for resuming your %(amount)s contribution - it is very much appreciated and it will go a long way in supporting our operations. Recurring donations, in particular, are vital to our sustainability. As an HKFP Patron, your contribution will be well-spent, allowing us to invest more in original reporting and safeguard press freedom. Please check out HKFP's latest Annual Report(https://hongkongfp.com/hong-kong-free-press-annual-report-2020/) - it includes our yearly, audited Transparency Report(https://hongkongfp.com/hong-kong-free-press-transparency-report-2019/), so you can see how carefully we spend our income.\n Sign into our support page (click "forgot password?" if you have trouble logging in) to adjust or suspend your donation(%(url)s). Please email [email protected] if you have any further enquiries.\n From all of us, thank you for helping us keep independent media alive in Hong Kong!\n Details of your recurring donation:\n \n Donor: %(name)s\n Recurring donation identifier: %(profile_id)s\n Payment method: %(gateway)s\n Recurring donation amount: %(amount)s\n Recurring Status: %(recurring_status)s\n \n Thank you,\n %(sitename)s""") % { 'name': subscription.user.fullname, 'url': reverse_with_site_url('donations:my-recurring-donations'), 'profile_id': subscription.profile_id, 'gateway': displayGateway(subscription), 'amount': displayRecurringAmountWithCurrency(subscription), 'recurring_status': subscription.recurring_status, 'sitename': get_site_name() }
def get_recurring_paused_admin_text(subscription): return _("""A Recurring Donation is paused\n \n Hi Admins,\n This email is to inform you that a recurring donation has been paused on your website:\n %(url)s\n \n Donor: %(name)s\n Recurring donation identifier: %(profile_id)s\n Payment method: %(gateway)s\n Recurring donation amount: %(amount)s\n Recurring Status: %(recurring_status)s\n \n Thank you,\n %(sitename)s""") % { 'url': reverse_with_site_url('donations_subscription_modeladmin_inspect', kwargs={'instance_pk': subscription.id}), 'name': subscription.user.fullname, 'profile_id': subscription.profile_id, 'gateway': subscription.gateway, 'amount': displayRecurringAmountWithCurrency(subscription), 'recurring_status': subscription.recurring_status, 'sitename': get_site_name() }
def get_donation_status_change_text(donation): donation_url = reverse_with_site_url( 'donations:my-renewals', kwargs={ 'id': donation.subscription.id }) if donation.is_recurring else reverse_with_site_url( 'donations:my-onetime-donations') if donation.user: url_text = str( _('Sign into our support page (click "forgot password?" if you have trouble logging in) to view your updated donation(%(url)s).' ) % {'url': donation_url}) + "\n" else: url_text = '' return _("""ONE-OFF DONATION STATUS UPDATED\n \n Dear %(name)s,\n %(url_text)s Details of your donation:\n \n Transaction ID: %(transaction_id)s\n Donation frequency: %(frequency)s\n Payment method: %(gateway)s\n Donation amount: %(amount)s\n Payment status: %(status)s\n \n Thank you,\n %(sitename)s""") % { 'name': donation.donor_name(), 'url_text': url_text, 'transaction_id': donation.transaction_id, 'frequency': donation.donation_frequency, 'gateway': displayGateway(donation), 'amount': displayDonationAmountWithCurrency(donation), 'status': donation.payment_status, 'sitename': get_site_name() }
def site_name_filter(var): """ This is a workaround I cannot find a way to simply assign a simple_tag value to a variable used in blocktrans(e.g. in unsubscription.html) So I resort to using a filter but ignoring the passed variable """ return get_site_name()
def get_account_deleted_donor_text(user): return _("""ACCOUNT DELETED\n \n Dear %(name)s,\n Thanks very much for your recent support.\n Your account at %(sitename)s has been deleted at your request.\n From all of us, thank you for backing our team and helping us keep independent media alive in Hong Kong!\n \n Thank you,\n %(sitename)s""") % { 'name': user.fullname, 'sitename': get_site_name() }
def get_donation_receipt_text(donation): donation_url = reverse_with_site_url( 'donations:my-recurring-donations' ) if donation.is_recurring else reverse_with_site_url( 'donations:my-onetime-donations') if donation.user: url_text = str( _('Sign into our support page (click "forgot password?" if you have trouble logging in) to view your donation(%(url)s). Please email [email protected] if you have any further enquiries.' ) % {'url': donation_url}) else: url_text = '' return _("""NEW ONE-OFF DONATION\n \n Dear %(name)s,\n A big "thank you" for your kind %(amount)s donation - it is very much appreciated and it will go a long way in supporting our operations.\n Your contribution will be well-spent, allowing us to invest more in original reporting and safeguard press freedom. Please check out HKFP's latest Annual Report(https://hongkongfp.com/hong-kong-free-press-annual-report-2020/) - it includes our yearly, audited Transparency Report(https://hongkongfp.com/hong-kong-free-press-transparency-report-2019/), so you can see how carefully we spend our income.\n %(url_text)s\n From all of us, thank you for helping us keep independent media alive in Hong Kong!\n Details of your donation:\n \n Transaction ID: %(transaction_id)s\n Donation frequency: %(frequency)s\n Payment method: %(gateway)s\n Donation amount: %(amount)s\n Payment status: %(status)s\n %(recurring_status)s \n Thank you,\n %(sitename)s""") % { 'name': donation.donor_name(), 'url_text': url_text, 'transaction_id': donation.transaction_id, 'frequency': donation.donation_frequency, 'gateway': displayGateway(donation), 'amount': displayDonationAmountWithCurrency(donation), 'status': donation.payment_status, 'recurring_status': 'Recurring Status: ' + donation.subscription.recurring_status + "\n" if donation.is_recurring and donation.subscription else '', 'sitename': get_site_name() }
def get_account_created_admin_text(user): return _("""A Donor Account is created\n \n Hi Admins,\n This email is to inform you that a donor account has been created on your website:\n %(url)s\n \n Donor: %(name)s\n \n Thank you,\n %(sitename)s""") % { 'url': get_site_url() + '/admin/users/%d/' % user.id, 'name': user.fullname, 'sitename': get_site_name() }
def get_donation_revoked_donor_text(donation): donation_url = reverse_with_site_url( 'donations:my-recurring-donations' ) if donation.is_recurring else reverse_with_site_url( 'donations:my-onetime-donations') if donation.user: url_text = str( _('Go to %(url)s to view your donation on the website.') % {'url': donation_url}) else: url_text = '' return _("""DONATION REVOKED\n \n Dear %(name)s,\n Your donation is unfortunately revoked by the payment gateway. %(url_text)s\n Here are the details of your donation:\n \n Transaction ID: %(transaction_id)s\n Donation frequency: %(frequency)s\n Payment method: %(gateway)s\n Donation amount: %(amount)s\n Payment status: %(status)s\n %(recurring_status)s \n Thank you,\n %(sitename)s""") % { 'name': donation.donor_name(), 'url_text': url_text, 'transaction_id': donation.transaction_id, 'frequency': donation.donation_frequency, 'gateway': displayGateway(donation), 'amount': displayDonationAmountWithCurrency(donation), 'status': donation.payment_status, 'recurring_status': 'Recurring Status: ' + donation.subscription.recurring_status + "\n" if donation.is_recurring and donation.subscription else '', 'sitename': get_site_name() }
def createSubscription(session, plan_id, donation, is_test=False): checkAccessTokenExpiry(session) paypalSettings = getPayPalSettings() api_url = paypalSettings.api_url + '/v1/billing/subscriptions' subscription_dict = { "plan_id": plan_id, "quantity": "1", "subscriber": { "name": { "given_name": getUserGivenName(donation.user), "surname": donation.user.last_name or '' }, "email_address": donation.user.email }, "application_context": { "brand_name": get_site_name(), "locale": "en-US", "shipping_preference": "NO_SHIPPING", "user_action": "SUBSCRIBE_NOW", "payment_method": { "payer_selected": "PAYPAL", "payee_preferred": "IMMEDIATE_PAYMENT_REQUIRED" }, "return_url": reverse_with_site_url('donations:return-from-paypal') if not is_test else 'http://example.com/return/', "cancel_url": reverse_with_site_url('donations:cancel-from-paypal') if not is_test else 'http://example.com/cancel/' }, "custom_id": str(donation.id) } if paypalSettings.sandbox_mode and session.get( 'negtest_createSubscription', None): subscription_dict['plan_id'] = session.get( 'negtest_createSubscription') return curlPaypal(api_url, common_headers(session['paypal_token']), post_data=json.dumps(subscription_dict))
def get_subscription_status_change_text(subscription): return _("""RECURRING DONATION STATUS UPDATED\n \n Dear %(name)s,\n Sign into our support page (click "forgot password?" if you have trouble logging in) to view your updated recurring donation(%(url)s).\n Details of your recurring donation:\n \n Profile ID: %(profile_id)s\n Payment method: %(gateway)s\n Recurring Amount: %(amount)s\n Status: %(status)s\n \n Thank you,\n %(sitename)s""") % { 'name': subscription.user.fullname, 'url': reverse_with_site_url('donations:my-recurring-donations'), 'profile_id': subscription.profile_id, 'gateway': displayGateway(subscription), 'amount': displayRecurringAmountWithCurrency(subscription), 'status': subscription.recurring_status, 'sitename': get_site_name() }
def get_donation_revoked_admin_text(donation): return _("""A Donation is revoked\n \n Hi Admins,\n This email is to inform you that a donation has been revoked on your website:\n %(url)s\n \n Donor: %(name)s\n Transaction ID: %(transaction_id)s\n Donation frequency: %(frequency)s\n Payment method: %(gateway)s\n Donation amount: %(amount)s\n Payment status: %(status)s\n %(recurring_status)s \n Thank you,\n %(sitename)s""") % { 'url': reverse_with_site_url('donations_donation_modeladmin_inspect', kwargs={'instance_pk': donation.id}), 'name': donation.donor_name(), 'transaction_id': donation.transaction_id, 'frequency': donation.donation_frequency, 'gateway': donation.gateway, 'amount': displayDonationAmountWithCurrency(donation), 'status': donation.payment_status, 'recurring_status': 'Recurring Status: ' + donation.subscription.recurring_status + "\n" if donation.is_recurring and donation.subscription else '', 'sitename': get_site_name() }
def site_name(): return get_site_name()
def redirect_to_gateway_url(self): """ Overriding parent implementation as 2C2P has to receive a form post from client browser. See docs https://developer.2c2p.com/docs/payment-requestresponse-parameters on recurring parameters behavior """ data = {} data['version'] = REDIRECT_API_VERSION data['merchant_id'] = self.settings.merchant_id data['order_id'] = self.donation.transaction_id data['currency'] = getCurrencyDictAt(self.donation.currency)['code'] # Beware: self.donation.donation_amount param is str in type data['amount'] = format_payment_amount(self.donation.donation_amount, self.donation.currency) # Apr 20 Tested result_url_1/2 working (such that merchant portal no need manual setting) after follow up with 2C2P Sum (an internal 2C2P settings needs to be turned on by them) # todo: Apr 21 2C2P server is not firing back the request from the new recurring payments (need follow up with Sum again) data['result_url_1'] = reverse_with_site_url( 'donations:return-from-2c2p') data['result_url_2'] = reverse_with_site_url( 'donations:verify-2c2p-response') data['user_defined_1'] = str(self.donation.id) if self.donation.is_recurring: data['payment_description'] = _( 'Recurring Donation for %(site)s') % { 'site': get_site_name() } data['request_3ds'] = 'Y' data['recurring'] = 'Y' data['order_prefix'] = gen_order_prefix_2c2p() data['recurring_amount'] = format_payment_amount( self.donation.donation_amount, self.donation.currency) data['allow_accumulate'] = 'N' data['recurring_count'] = 0 data['payment_option'] = 'A' # - daily recurring for testing data['recurring_interval'] = 1 data['charge_next_date'] = getNextDateFromRecurringInterval( data['recurring_interval'], '%d%m%Y') # - monthly recurring(normal behavior) # getRecurringDateNextMonth requires the superuser to set the timezone first # data['charge_on_date'] = getRecurringDateNextMonth('%d%m') # append order_prefix to donation metas for distinguishment # dpmeta = DonationPaymentMeta( # donation=self.donation, field_key='order_prefix', field_value=data['order_prefix']) # dpmeta.save() else: data['payment_description'] = _( 'Onetime Donation for %(site)s') % { 'site': get_site_name() } params = '' for key in getRequestParamOrder(): if key in data.keys(): params += str(data[key]) # python 3.6 code data['hash_value'] = hmac.new(bytes(self.settings.secret_key, 'utf-8'), bytes(params, 'utf-8'), hashlib.sha256).hexdigest() return render(self.request, 'donations/redirection_2c2p_form.html', { 'action': self.base_gateway_redirect_url(), 'data': data })