def process_art_show_payment(self, session, id): attendee = session.attendee(id) charge = Charge(attendee, description="Art show application payment") stripe_intent = charge.create_stripe_intent(session) message = stripe_intent if isinstance(stripe_intent, string_types) else '' if message: return {'error': message} else: for app in attendee.art_show_applications: app.status = c.PAID # This needs to accommodate payment cancellations send_email.delay( c.ADMIN_EMAIL, c.ART_SHOW_EMAIL, 'Art Show Payment Received', render('emails/art_show/payment_notification.txt', {'app': app}, encoding=None), model=app.to_dict('id')) send_email.delay( c.ART_SHOW_EMAIL, app.email, 'Art Show Payment Received', render('emails/art_show/payment_confirmation.txt', {'app': app}, encoding=None), model=app.to_dict('id')) if attendee.paid == c.NOT_PAID: attendee.paid = c.HAS_PAID session.add(session.create_receipt_item(attendee, charge.amount, "Art show payment", charge.stripe_transaction)) session.add(attendee) session.commit() return {'stripe_intent': stripe_intent, 'success_url': 'edit?id={}&message={}'.format(attendee.art_show_applications[0].id, 'Your payment has been accepted')}
def arbitrary_charge(self, session, id, amount, description, email, return_to='arbitrary_charge_form'): charge = Charge(amount=100 * int(amount), description=description, receipt_email=email) stripe_intent = charge.create_stripe_intent(session) message = stripe_intent if isinstance(stripe_intent, string_types) else '' if message: return {'error': message} else: session.add( ArbitraryCharge( amount=charge.dollar_amount, what=charge.description, reg_station=cherrypy.session.get('reg_station'))) return { 'stripe_intent': stripe_intent, 'success_url': '{}?message={}'.format(return_to, 'Charge successfully processed'), 'cancel_url': 'cancel_arbitrary_charge' }
def purchases_charge(self, session, id, amount, receipt_id): receipt = session.art_show_receipt(receipt_id) attendee = session.attendee(id) charge = Charge( attendee, amount=amount, description='{}ayment for {}\'s art show purchases'.format( 'P' if int(amount) == receipt.total else 'Partial p', attendee.full_name)) stripe_intent = charge.create_stripe_intent(session) message = stripe_intent if isinstance(stripe_intent, string_types) else '' if message: return {'error': message} else: session.add( ArtShowPayment( receipt=receipt, amount=charge.amount, type=c.STRIPE, )) session.commit() return { 'stripe_intent': stripe_intent, 'success_url': 'pieces_bought?id={}&message={}'.format( attendee.id, 'Charge successfully processed') }
def take_payment(self, session, id): attendee = session.attendee(id) charge = Charge(attendee, amount=attendee.amount_unpaid * 100) stripe_intent = charge.create_stripe_intent(session) message = stripe_intent if isinstance(stripe_intent, string_types) else '' if message: return {'error': message} else: db_attendee = session.query(Attendee).filter_by( id=attendee.id).first() if db_attendee: attendee = db_attendee session.add( session.create_receipt_item(attendee, charge.amount, "At-door kiosk payment", charge.stripe_transaction)) session.add(attendee) session.commit() return { 'stripe_intent': stripe_intent, 'success_url': 'register?message={}'.format(c.AT_DOOR_PREPAID_MSG) }
def index(self, message=''): if not Charge.unpaid_preregs: raise HTTPRedirect('form?message={}', message) if message else HTTPRedirect('form') else: return { 'message': message, 'charge': Charge(listify(Charge.unpaid_preregs.values())) }
def pay(self, session, id, message=''): attendee = session.attendee(id) if attendee.paid != c.NOT_PAID: raise HTTPRedirect('register?message={}', c.AT_DOOR_NOPAY_MSG) else: return { 'message': message, 'attendee': attendee, 'charge': Charge(attendee, description=attendee.full_name) }
def test_charge_log_transaction(self, monkeypatch): attendee = Attendee() monkeypatch.setattr(Attendee, 'amount_unpaid', 10) charge = Charge(targets=[attendee], amount=1000, description="Test charge") charge.response = stripe.Charge(id=10) result = charge.stripe_transaction_from_charge() assert result.stripe_id == 10 assert result.amount == 1000 assert result.desc == "Test charge" assert result.type == c.PAYMENT assert result.who == 'non-admin'
def process_marketplace_payment(self, session, id): attendee = session.attendee(id) charge = Charge( attendee, description="Marketplace application payment for {}".format( attendee.full_name)) stripe_intent = charge.create_stripe_intent(session) message = stripe_intent if isinstance(stripe_intent, string_types) else '' if message: return {'error': message} else: if attendee.marketplace_cost: for app in attendee.marketplace_applications: cancel_amt = app.amount_unpaid app.amount_paid += app.amount_unpaid send_email.delay( c.ADMIN_EMAIL, c.MARKETPLACE_APP_EMAIL, 'Marketplace Payment Received', render('emails/marketplace/payment_notification.txt', {'app': app}, encoding=None), model=app.to_dict('id')) send_email.delay( c.MARKETPLACE_APP_EMAIL, app.email_to_address, 'Marketplace Payment Received', render('emails/marketplace/payment_confirmation.txt', {'app': app}, encoding=None), model=app.to_dict('id')) if attendee.paid == c.NOT_PAID: attendee.paid = c.HAS_PAID session.add( session.create_receipt_item(attendee, charge.amount, "Marketplace payment", charge.stripe_transaction)) session.add(attendee) session.commit() return { 'stripe_intent': stripe_intent, 'success_url': 'edit?id={}&message={}'.format( attendee.marketplace_applications[0].id, 'Your payment has been accepted'), 'cancel_url': '../preregistration/cancel_payment?model_id={}&cancel_amt={}'. format(attendee.marketplace_applications[0].id, cancel_amt) }
def index(self, session, message=''): if not Charge.unpaid_preregs: raise HTTPRedirect('form?message={}', message) if message else HTTPRedirect('form') else: charge = Charge(listify(Charge.unpaid_preregs.values())) for attendee in charge.attendees: if attendee.promo_code and attendee.promo_code.group: attendee.group_name = session.query(PromoCode).filter_by( code=attendee.promo_code.code).first().group.name return {'message': message, 'charge': charge}
def test_charge_log_transaction_no_unpaid(self, monkeypatch): group = Group() monkeypatch.setattr(Group, 'amount_unpaid', 0) charge = Charge(targets=[group], amount=1000, description="Test charge") charge.response = stripe.Charge(id=10) txn = charge.stripe_transaction_from_charge() result = charge.stripe_transaction_for_model(group, txn) assert result.group_id == group.id assert result.txn_id == txn.id assert result.share == 1000
def test_charge_log_transaction_attendee(self, monkeypatch): attendee = Attendee() monkeypatch.setattr(Attendee, 'amount_unpaid', 10) charge = Charge(targets=[attendee], description="Test charge") charge.response = stripe.Charge(id=10) txn = charge.stripe_transaction_from_charge() result = charge.stripe_transaction_for_model(attendee, txn) assert result.attendee_id == attendee.id assert result.txn_id == txn.id assert result.share == 1000
def test_charge_log_transaction(self): attendee = Attendee() charge = Charge(targets=[attendee], amount=1000, description="Test charge") charge.response = stripe.Charge(id=10) result = charge.stripe_transaction_from_charge() assert result.stripe_id == 10 assert result.amount == 1000 assert result.desc == "Test charge" assert result.type == c.PAYMENT assert result.who == 'non-admin' assert result.fk_id == attendee.id assert result.fk_model == attendee.__class__.__name__
def pay(self, session, id, message=''): attendee = session.attendee(id) if attendee.paid != c.NOT_PAID: raise HTTPRedirect( 'register?message={}', 'You are already paid (or registered for a free badge) ' 'and should proceed to the preregistration desk to pick up your badge') else: return { 'message': message, 'attendee': attendee, 'charge': Charge(attendee, description=attendee.full_name) }
def attendee_donation_form(self, session, id, message=''): attendee = session.attendee(id) if attendee.amount_unpaid <= 0: raise HTTPRedirect('confirm?id={}', id) if 'attendee_donation_form' not in attendee.payment_page: raise HTTPRedirect(attendee.payment_page) return { 'message': message, 'attendee': attendee, 'charge': Charge( attendee, description='{}{}'.format(attendee.full_name, '' if attendee.overridden_price else ' kicking in extra')) }
def add_group_members(self, session, id, count): group = session.group(id) if int(count ) < group.min_badges_addable and not group.is_in_grace_period: raise HTTPRedirect( 'group_members?id={}&message={}', group.id, 'This group cannot add fewer than {} badges'.format( group.min_badges_addable)) charge = Charge(group, amount=100 * int(count) * group.new_badge_cost, description='{} extra badges for {}'.format( count, group.name)) return {'count': count, 'group': group, 'charge': charge}
def process_free_prereg(self, session): charge = Charge(listify(Charge.unpaid_preregs.values())) if charge.total_cost <= 0: for attendee in charge.attendees: session.add(attendee) for group in charge.groups: session.add(group) Charge.unpaid_preregs.clear() Charge.paid_preregs.extend(charge.targets) raise HTTPRedirect('paid_preregistrations?payment_received={}', charge.dollar_amount) else: message = "These badges aren't free! Please pay for them." raise HTTPRedirect('index?message={}', message)
def add_promo_codes(self, session, id, count): group = session.promo_code_group(id) if int(count ) < group.min_badges_addable and not group.is_in_grace_period: raise HTTPRedirect( 'group_promo_codes?id={}&message={}', group.id, 'You must add at least {} codes'.format( group.min_badges_addable)) charge = Charge(group.buyer, amount=100 * int(count) * c.get_group_price(), description='{} extra badge{} for {}'.format( count, 's' if int(count) > 1 else '', group.name)) return {'count': count, 'group': group, 'charge': charge}
def arbitrary_charge_form(self, message='', amount=None, description=''): charge = None if amount is not None: if not amount.isdigit() or not (1 <= int(amount) <= 999): message = 'Amount must be a dollar amount between $1 and $999' elif not description: message = "You must enter a brief description of what's being sold" else: charge = Charge(amount=100 * int(amount), description=description) return { 'charge': charge, 'message': message, 'amount': amount, 'description': description }
def manual_reg_charge(self, session, id): attendee = session.attendee(id) charge = Charge(attendee, amount=attendee.amount_unpaid * 100) stripe_intent = charge.create_stripe_intent(session) message = stripe_intent if isinstance(stripe_intent, string_types) else '' if message: return {'error': message} else: attendee.payment_method = c.MANUAL session.add( session.create_receipt_item(attendee, charge.amount, "At-door desk payment", charge.stripe_transaction)) session.merge(attendee) session.commit() return {'stripe_intent': stripe_intent, 'success_url': ''}
def sales_charge_form(self, message='', amount=None, description='', sale_id=None): charge = None if amount is not None: if not description: message = "You must enter a brief description " \ "of what's being sold" else: charge = Charge(amount=int(100 * float(amount)), description=description) return { 'charge': charge, 'message': message, 'amount': amount, 'description': description, 'sale_id': sale_id }
def group_members(self, session, id, message='', **params): group = session.group(id) charge = Charge(group) if group.status != c.APPROVED and 'name' in params: # Both the Attendee class and Group class have identically named # address fields. In order to distinguish the two sets of address # fields in the params, the Group fields are prefixed with "group_" # when the form is submitted. To prevent instantiating the Group object # with the Attendee's address fields, we must clone the params and # rename all the "group_" fields. group_params = dict(params) for field_name in [ 'country', 'region', 'zip_code', 'address1', 'address2', 'city' ]: group_params[field_name] = params.get( 'group_{}'.format(field_name), '') group.apply(group_params, restricted=True) message = check(group, prereg=True) if message: session.rollback() else: session.commit() if group.is_dealer: send_email.delay( c.MARKETPLACE_EMAIL, c.MARKETPLACE_EMAIL, 'Dealer Application Changed', render('emails/dealers/appchange_notification.html', {'group': group}, encoding=None), 'html', model=group.to_dict('id')) message = 'Thank you! Your application has been updated.' raise HTTPRedirect('group_members?id={}&message={}', group.id, message) return {'group': group, 'charge': charge, 'message': message}
def sales_charge(self, session, id, amount, description): charge = Charge(amount=100 * float(amount), description=description) stripe_intent = charge.create_stripe_intent(session) message = stripe_intent if isinstance(stripe_intent, string_types) else '' if message: return {'error': message} else: session.add( ArbitraryCharge( amount=charge.dollar_amount, what=charge.description, )) return { 'stripe_intent': stripe_intent, 'success_url': 'sales_charge_form?message={}'.format( 'Charge successfully processed'), 'cancel_url': '../merch_admin/cancel_arbitrary_charge' }
def group_members(self, session, id, message='', **params): group = session.group(id) charge = Charge(group) if cherrypy.request.method == 'POST': # Both the Attendee class and Group class have identically named # address fields. In order to distinguish the two sets of address # fields in the params, the Group fields are prefixed with "group_" # when the form is submitted. To prevent instantiating the Group object # with the Attendee's address fields, we must clone the params and # rename all the "group_" fields. group_params = dict(params) for field_name in ['country', 'region', 'zip_code', 'address1', 'address2', 'city']: group_params[field_name] = params.get('group_{}'.format(field_name), '') group.apply(group_params, restricted=True) message = check(group, prereg=True) if message: session.rollback() else: session.commit() if group.is_dealer: send_email.delay( c.MARKETPLACE_EMAIL, c.MARKETPLACE_EMAIL, '{} Changed'.format(c.DEALER_APP_TERM.title()), render('emails/dealers/appchange_notification.html', {'group': group}, encoding=None), 'html', model=group.to_dict('id')) message = 'Thank you! Your application has been updated.' raise HTTPRedirect('group_members?id={}&message={}', group.id, message) return { 'group': group, 'upgraded_badges': len([a for a in group.attendees if a.badge_type in c.BADGE_TYPE_PRICES]), 'charge': charge, 'message': message }
def edit(self, session, message='', **params): app = session.marketplace_application(params, restricted=True, ignore_csrf=True) return_to = params['return_to'] \ if 'return_to' in params else '/marketplace/edit' if 'id' not in params: message = 'Invalid marketplace application ID. ' \ 'Please try going back in your browser.' if cherrypy.request.method == 'POST': message = check(app, prereg=True) if not message: session.add(app) session.commit( ) # Make sure we update the DB or the email will be wrong! send_email.delay( c.MARKETPLACE_APP_EMAIL, app.email, 'Marketplace Application Updated', render('emails/marketplace/appchange_notification.html', {'app': app}, encoding=None), 'html', model=app.to_dict('id')) raise HTTPRedirect('..{}?id={}&message={}', return_to, app.id, 'Your application has been updated') else: session.rollback() return { 'message': message, 'app': app, 'return_to': 'edit', 'charge': Charge(app.attendee) }
def pieces_bought(self, session, id, search_text='', message='', **params): try: receipt = session.art_show_receipt(id) except: attendee = session.attendee(id) if not attendee.art_show_receipt: receipt = ArtShowReceipt(attendee=attendee) session.add(receipt) session.commit() else: receipt = attendee.art_show_receipt else: attendee = receipt.attendee must_choose = False unclaimed_pieces = [] unpaid_pieces = [] charge = None if search_text: if re.match('\w+-[0-9]+', search_text): artist_id, piece_id = search_text.split('-') pieces = session.query(ArtShowPiece).join( ArtShowPiece.app).filter( ArtShowPiece.piece_id == int(piece_id), ArtShowApplication.artist_id == artist_id.upper()) else: pieces = session.query(ArtShowPiece).filter( ArtShowPiece.name.ilike('%{}%'.format(search_text))) unclaimed_pieces = pieces.filter(ArtShowPiece.buyer == None, ArtShowPiece.status != c.RETURN) unclaimed_pieces = [ piece for piece in unclaimed_pieces if piece.sale_price > 0 ] unpaid_pieces = pieces.join(ArtShowReceipt).filter( ArtShowReceipt.closed != None, ArtShowPiece.status != c.PAID) unpaid_pieces = [ piece for piece in unpaid_pieces if piece.sale_price > 0 ] if pieces.count() == 0: message = "No pieces found with ID or title {}.".format( search_text) elif len(unclaimed_pieces) == 0 and len(unpaid_pieces) == 0: if pieces.count() == 1: msg_piece = pieces.one() if msg_piece.receipt == receipt: message = "That piece ({}) is already on this receipt.".format( msg_piece.artist_and_piece_id) elif msg_piece.sale_price <= 0: message = "That piece ({}) doesn't have a valid sale price." \ .format(msg_piece.artist_and_piece_id) elif msg_piece.status == c.RETURN: message = "That piece ({}) is marked {}.".format( msg_piece.artist_and_piece_id, msg_piece.status_label) elif msg_piece in attendee.art_show_purchases: message = "That piece ({}) was already sold to this buyer."\ .format(msg_piece.artist_and_piece_id) else: message = "That piece ({}) was already sold to another buyer."\ .format(msg_piece.artist_and_piece_id) else: message = "None of the matching pieces for '{}' can be claimed.".format( search_text) elif len(unclaimed_pieces) > 1 or (len(unclaimed_pieces) == 0 and len(unpaid_pieces) > 1): message = "There were multiple pieces found matching '{}.' Please choose one.".format( search_text) must_choose = True if not message: if len(unclaimed_pieces) == 0 and len(unpaid_pieces) == 1: piece = unpaid_pieces[0] elif len(unclaimed_pieces) == 1: piece = unclaimed_pieces[0] else: message = "Something went wrong! Try again?" if not message: piece.receipt = receipt session.add(piece) message = 'Piece {} successfully claimed'.format( piece.artist_and_piece_id) if not must_choose: raise HTTPRedirect('pieces_bought?id={}&message={}', receipt.id, message) elif 'amount' in params: if params['amount']: amount = int(Decimal(params['amount']) * 100) else: amount = receipt.owed charge = Charge( targets=[attendee], amount=amount, description='{}ayment for {}\'s art show purchases'.format( 'P' if amount == receipt.total else 'Partial p', attendee.full_name)) return { 'receipt': receipt, 'message': message, 'must_choose': must_choose, 'pieces': unclaimed_pieces or unpaid_pieces, 'charge': charge, }
def test_charge_log_transaction_no_model(self): stripe.Charge.create = Mock(return_value=1) Charge.stripe_transaction_from_charge = Mock() charge = Charge(amount=1000, description="Test charge") Charge.charge_cc(charge, Mock(), 1) assert not Charge.stripe_transaction_from_charge.called
def test_charge_one_email(self): attendee = Attendee(email='*****@*****.**') charge = Charge(targets=[attendee]) assert charge.receipt_email == attendee.email
def test_charge_group_leader_email(self): attendee = Attendee(email='*****@*****.**') group = Group(attendees=[attendee]) charge = Charge(targets=[group]) assert charge.receipt_email == attendee.email
def test_charge_no_email(self): charge = Charge(targets=[Group()]) assert charge.receipt_email is None
def test_charge_first_email(self): attendee = Attendee(email='*****@*****.**') charge = Charge(targets=[attendee, Attendee(email='*****@*****.**'), Attendee(email='*****@*****.**')]) assert charge.receipt_email == attendee.email