예제 #1
0
def send_payment_notification():
  logger.info('Sending payment notification')

  with transaction.atomic():
    finished_purchases = Purchase.objects.filter(
      payment_status__in=[PaymentStatusName.SUCCESS.value, PaymentStatusName.FAILED.value],
      confirmation_sent=False
    )
    logger.info('Found: {} finished payments.'.format(finished_purchases.count()))

    for purchase in finished_purchases:
      completed = purchase.payment_status == PaymentStatusName.SUCCESS.value
      subject = 'Purchase completed [{}]'.format(purchase.id) if completed else 'Purchase failed [{}]'.format(
        purchase.id)
      user = purchase.user
      template = 'completed' if completed else 'failed'

      send_mail.delay(
        [user.email],
        subject,
        get_rendered_template('mail/purchase/{}.txt'.format(template),
                              {'name': user.first_name, 'purchase_id': purchase.id}),
        get_rendered_template('mail/purchase/{}.html'.format(template),
                              {'name': user.first_name, 'purchase_id': purchase.id}),
        ['*****@*****.**']
      )

      purchase.confirmation_sent = True
      purchase.save()
예제 #2
0
def send_mail(to, title, messageTXT, messageHTML, bcc=None, attachment=[]):
  '''
  :param to:
  :param title:
  :param messageTXT:
  :param messageHTML:
  :param bcc:
  :param attachment: (filename, content, mimetype)
  :return:
  '''
  logger.info(
    'Sending email to: {}, title: {}, messageTXT: {}, messageHTML: {}, bcc: {}, attachment: {}'.format(to, title,
                                                                                                       messageTXT,
                                                                                                       messageHTML, bcc,
                                                                                                       bool(
                                                                                                         attachment)))
  email = EmailMultiAlternatives(
    subject=title,
    body=messageTXT,
    from_email='*****@*****.**',
    to=to,
    bcc=bcc,
    attachments=attachment and [attachment] or []
  )
  email.attach_alternative(messageHTML, "text/html")
  email.send()
예제 #3
0
def check_payu_payment_status():
  logger.info('Checking payment status.')
  with transaction.atomic():

    pending_purchases = Purchase.objects.filter(
      payment_status__in=[PaymentStatusName.PENDING.value, PaymentStatusName.STARTED.value],
      payment_type=PaymentTypeName.PAYU.value
    )
    logger.info('Found: {} pending payments.'.format(pending_purchases.count()))

    for purchase in pending_purchases:

      purchase_id = purchase.id
      logger.info('Checking payment status for purchase: {}, current payment status: {}'.format(
        purchase_id, purchase.payment_status
      ))
      payu_payment = purchase.payu_payment
      payu_payment_status = payu_payment.payment_status

      logger.info('Current PayU status: {}, purchase: {}'.format(payu_payment_status, purchase_id))

      if payu_payment_status.lower() == PayUPaymentStatus.STATUS_COMPLETED:
        purchase.payment_status = PaymentStatusName.SUCCESS.value
      elif payu_payment_status.lower() == PayUPaymentStatus.STATUS_FAILED:
        purchase.payment_status = PaymentStatusName.FAILED.value
      elif payu_payment_status.lower() == PayUPaymentStatus.STATUS_STARTED:
        purchase.payment_status = PaymentStatusName.STARTED.value

      logger.info('New purchase status: {}, purchase: {}'.format(purchase.payment_status, purchase_id))

      purchase.save()

  return None
예제 #4
0
def __find_workshops_for_query(query):
  search_results = SearchQuerySet().models(Workshop).filter(text__in=query.split()).load_all()
  valid_results = [result for result in search_results if result is not None]
  for result in valid_results:
    logger.info('Found result with id: {:<30} and score: {}'.format(result.id, result.score))

  return [search_result.object for search_result in search_results]
예제 #5
0
def _get_or_generate_token(user):
    try:
        return Token.objects.get(user=user)
    except Token.DoesNotExist:
        logger.info(
            'No token found for user: %s. New token will be generated.'.format(
                user.id))
        return Token.objects.create(user=user)
예제 #6
0
def rebuild_workshops_full_text_search():
  logger.info('Updating workshop full-text search index.')
  try:
    rebuild_index.Command().handle(using=['default'], verbosity=2, remove=True, noinput=True)
  except Exception as e:
    logger.error('Caught exception while updating workshop index: %s' % e)

  return None
예제 #7
0
def _calculate_price(user, product, discount):
    price_net = product.price_net
    if discount:
        price_net = int(price_net - (price_net * discount) / 100)
        logger.info('New price for user: {} is: {}'.format(user.id, price_net))
    price_vat_value = product.price_vat
    price_total = int(price_net + price_net * price_vat_value)

    logger.info('User: {}, price net: {}, price total: {}'.format(user.id, price_net, price_total))

    return (price_net, price_total)
예제 #8
0
def search_workshops(request, **kwargs):
  payload = request.DATA

  __validate_search_workshops_payload(payload)

  query = payload['query']

  logger.info('Looking for workshops for query: {}'.format(query))

  workshops = __find_workshops_for_query(query)

  return prepare_list_of_workshops_response(workshops)
예제 #9
0
    def __execute_post_request(headers, request_content, url):
        response = requests.post(url, data=request_content, headers=headers)
        response_dict = json.loads(response.content.decode("utf-8"), 'utf-8')
        if "response" not in response_dict:
            raise PythonIfirmaExceptionFactory.throw_exception_by_code(-1)
        real_response_content = response_dict["response"]
        logger.info('ifirma response: {}'.format(real_response_content))
        response_code = real_response_content.get("Kod", -1)

        if response_code != 0:
            raise PythonIfirmaExceptionFactory.throw_exception_by_code(response_code)

        return response_dict
예제 #10
0
def _get_purchase_invoice_data_or_none(purchase):
    try:
        invoice = PurchaseInvoice.objects.get(purchase=purchase)
        return {
            'name': invoice.name,
            'street': invoice.street,
            'city': invoice.city,
            'zipCode': invoice.zip_code,
            'country': invoice.country,
            'taxId': invoice.tax_id,
        }
    except PurchaseInvoice.DoesNotExist as e:
        logger.info('Skipping invoice processing, no invoice for purchase: {}, err: {}'.format(purchase.id, str(e)))
        return None
예제 #11
0
    def __execute_post_request(headers, request_content, url):
        response = requests.post(url, data=request_content, headers=headers)
        response_dict = json.loads(response.content.decode("utf-8"), 'utf-8')
        if "response" not in response_dict:
            raise PythonIfirmaExceptionFactory.throw_exception_by_code(-1)
        real_response_content = response_dict["response"]
        logger.info('ifirma response: {}'.format(real_response_content))
        response_code = real_response_content.get("Kod", -1)

        if response_code != 0:
            raise PythonIfirmaExceptionFactory.throw_exception_by_code(
                response_code)

        return response_dict
예제 #12
0
def delete_workshop_message(request, **kwargs):
  workshop_id = kwargs['workshop_id']
  find_workshop_for_id_or_raise(workshop_id)

  message_id = kwargs['message_id']
  message = find_message_for_id_or_raise(message_id)

  user = request.user

  _check_if_user_is_author_of_message_or_workshop_mentor(message, user)

  logger.info('User with ID: {}, deletes messages with ID: {}'.format(user.id, message.id))

  message.delete()

  return Response(status=HTTP_204_NO_CONTENT)
예제 #13
0
def reset_pass_initialize(request, **kwargs):
    payload = request.DATA

    validate_payload_with_schema(payload, reset_pass_initialize_req_schema)

    email = payload['email']

    logger.info('Starting reset password process for: {}'.format(email))

    user = __find_user_auth_for_email(email)

    if user is not None:
        __remove_previous_reset_pw_attempts(email)
        reset_pw = __create_new_reset_password(email)
        reset_pw_link = __prepare_reset_pw_link(reset_pw.token)

        __send_reset_pw_email(email, reset_pw_link)

    return Response(status=HTTP_204_NO_CONTENT)
예제 #14
0
def reset_pass_initialize(request, **kwargs):
  payload = request.DATA

  validate_payload_with_schema(payload, reset_pass_initialize_req_schema)

  email = payload['email']

  logger.info('Starting reset password process for: {}'.format(email))

  user = __find_user_auth_for_email(email)

  if user is not None:
    __remove_previous_reset_pw_attempts(email)
    reset_pw = __create_new_reset_password(email)
    reset_pw_link = __prepare_reset_pw_link(reset_pw.token)

    __send_reset_pw_email(email, reset_pw_link)

  return Response(status=HTTP_204_NO_CONTENT)
예제 #15
0
def __check_if_user_has_successful_purchase(user, workshop_id):
  try:
    return Purchase.objects.get(user=user, payment_status=PaymentStatusName.SUCCESS.value)
  except Purchase.DoesNotExist as e:
    logger.error(
      'No purchase found for user with ID: {} when signing for workshop with ID: {}, err: {}'.format(
        user.id,
        workshop_id,
        str(e))
    )
    try:
      purchase = Purchase.objects.get(user=user)
      logger.info('User with ID: {} has purchase with ID: {}, status: {}, payment type: {}'.format(
        user.id, purchase.id, purchase.payment_status, purchase.payment_type)
      )
    except Purchase.DoesNotExist:
      pass

    raise WorkshopWithoutPurchaseSignAttemptException(user.id)
예제 #16
0
def __check_if_tickets_limit_exceeded_but_honor_100_discount(promo_code):
    all_purchases = _count_success_purchases()

    organizers_purchases = _count_organizers_purchases()
    volunteers_purchases = _count_volunteers_purchases()
    speakers_purchases = _count_speakers_purchases()
    sponsors_staff_purchases = _count_sponsors_staff_purchases()
    sum_excluded = sum([organizers_purchases, volunteers_purchases, speakers_purchases, sponsors_staff_purchases, ])

    purchases_limit = settings.MAX_TICKETS

    logger.info(
        'Success purchases: {}, sum excluded: {}, free: {}'.format(all_purchases, sum_excluded,
                                                                   purchases_limit - all_purchases + sum_excluded)
    )

    is_100_discount = __is_100_discount_promo_code(promo_code)

    if ((all_purchases - sum_excluded) >= purchases_limit) and (not is_100_discount):
        raise TicketsLimitExceededException()
예제 #17
0
def generate_and_send_invoice():
  logger.info('Generating and sending invoices.')

  unsent_invoices = PurchaseInvoice.objects.filter(
    sent=False,
    purchase__payment_status=PaymentStatusName.SUCCESS.value,
    purchase__confirmation_sent=True
  )

  logger.info('Found: {} unsent invoices.'.format(unsent_invoices.count()))

  for invoice in unsent_invoices:
    with transaction.atomic():
      try:

        purchase = invoice.purchase
        logger.info('Generating invoice for purchase: {}'.format(purchase.id))

        client = iFirmaClient(
          invoice.name,
          invoice.tax_id,
          iFirmaAddress(
            invoice.city,
            invoice.zip_code,
            invoice.street,
            invoice.country,
          )
        )
        position = iFirmaItem(
          VAT.VAT_23,
          1,
          float("{0:.2f}".format(purchase.price_total / 100.0)),
          u"Bilet wstępu na warsztaty codepot.pl: {}".format(purchase.id),
          "szt."
        )
        ifirma_invoice = iFirmaInvoiceParams(client, [position])
        (ifirma_invoice_id, ifirma_invoice_no) = _ifirma_client.generate_invoice(ifirma_invoice)
        ifirma_invoice_pdf = _ifirma_client.get_invoice_pdf(ifirma_invoice_id)

        invoice.ifirma_id = ifirma_invoice_id
        send_mail(
          [purchase.user.email],
          'Payment completed [{}]'.format(purchase.id),
          get_rendered_template(
            'mail/purchase/invoice.txt',
            {'name': purchase.user.first_name, 'purchase_id': purchase.id}
          ),
          get_rendered_template(
            'mail/purchase/invoice.html',
            {'name': purchase.user.first_name, 'purchase_id': purchase.id}
          ),
          ['*****@*****.**'],
          ('{}.pdf'.format(ifirma_invoice_no), ifirma_invoice_pdf.getvalue(), 'application/pdf')
        )
        invoice.no = ifirma_invoice_no
        invoice.sent = True

        invoice.save()
      except Exception as e:
        logger.error('Error while generating invoice for purchase: {}, err: {}.'.format(purchase.id, str(e)))
        continue
예제 #18
0
 def save(self, *args, **kwargs):
     if self.usage_limit == 0:
         self.active = False
         logger.info('Setting promo code: {} to inactive.'.format(
             self.code))
     super(PromoCode, self).save(*args, **kwargs)
예제 #19
0
 def i(msg):
     logger.info(msg)
예제 #20
0
 def i(msg):
     logger.info(msg)
예제 #21
0
def _update_workshop_full_text_search_index(**kwargs):
    logger.info('Rebuilding workshops full text search index.')
    rebuild_workshops_full_text_search.delay()
예제 #22
0
def _get_or_generate_token(user):
    try:
        return Token.objects.get(user=user)
    except Token.DoesNotExist:
        logger.info('No token found for user: %s. New token will be generated.'.format(user.id))
        return Token.objects.create(user=user)
예제 #23
0
def handle_new_purchase(request, **kwargs):
    _check_if_registration_open()

    payload = request.DATA

    code = payload['promoCode']

    __check_if_tickets_limit_exceeded_but_honor_100_discount(code)

    user = request.user

    _check_if_user_has_purchase(user)

    logger.info('Handling new purchase for user: {} and payload: {}'.format(user.id, payload))

    invoice = payload['invoice']
    product_id = payload['productId']
    payment_type = payload['paymentType']
    payment_req_info = payload['paymentInfo']

    product = _find_and_validate_product(product_id)

    _validate_payment_info(payment_type, payment_req_info)

    _increment_tickets_purchased(product.price_tier)

    purchase = Purchase()
    purchase.user = user
    purchase.payment_type = payment_type
    purchase.product = product
    purchase.payment_status = PaymentStatusName.PENDING.value
    purchase.save()
    discount = None

    if code:
        promo_code = _find_and_validate_promo_code(code)

        purchase.promo_code = promo_code
        promo_code.usage_limit -= 1
        promo_code.save()
        discount = promo_code.discount

        logger.info('Found promo code: {} for user: {}, discount: {}'.format(code, user.id, discount))

        if discount == 100:
            logger.info('Found 100% discount for user: {} and promo code: {}'.format(user.id, code))
            classification = promo_code.classification
            is_group_purchase = classification and classification.name.startswith('group') or False
            purchase.payment_type = is_group_purchase and PaymentTypeName.GROUP.value or PaymentTypeName.FREE.value
            purchase.payment_status = PaymentStatusName.SUCCESS.value
            purchase.save()
            return Response(build_purchase_response(purchase), HTTP_201_CREATED)

    if invoice:
        _set_invoice_data(purchase, invoice)

    (price_net, price_total) = _calculate_price(user, product, discount)
    purchase.price_net = price_net
    purchase.price_total = price_total

    if payment_type == PaymentTypeName.PAYU.value:
        redirect_link = payment_req_info['redirectLink']
        _handle_payu_payment(user, request.META['REMOTE_ADDR'], price_total, purchase, redirect_link)
    elif payment_type == PaymentTypeName.TRANSFER.value:
        purchase.notes = 'To pay net: {}, total: {}'.format(price_net, price_total)
        purchase.payu_payment = None

    purchase.save()

    return Response(build_purchase_response(purchase), HTTP_201_CREATED)
예제 #24
0
 def save(self, *args, **kwargs):
     if self.usage_limit == 0:
         self.active = False
         logger.info('Setting promo code: {} to inactive.'.format(self.code))
     super(PromoCode, self).save(*args, **kwargs)
예제 #25
0
def _update_workshop_full_text_search_index(**kwargs):
  logger.info('Rebuilding workshops full text search index.')
  rebuild_workshops_full_text_search.delay()