Example #1
0
def create_task_if_not_order(customer_id):
    customer = Customer.get_by_id(customer_id)
    # Check if the customer has linked his credit card after he clicked the 'pay' button
    # If he didn't (one hour after the last time he tried to pay), create a new ShopTask to call this customer.
    if not customer.stripe_valid and customer.team_id:
        if customer.prospect_id:
            rmt, prospect = db.get([
                RegioManagerTeam.create_key(customer.team_id),
                Prospect.create_key(customer.prospect_id)
            ])
        else:
            prospect = create_prospect_from_customer(customer)
            rmt = RegioManagerTeam.get(
                RegioManagerTeam.create_key(customer.team_id))
        azzert(rmt.support_manager,
               'No support manager found for team %s' % rmt.name)
        task = create_task(
            prospect_or_key=prospect,
            status=ShopTask.STATUS_NEW,
            task_type=ShopTask.TYPE_SUPPORT_NEEDED,
            address=None,
            created_by=STORE_MANAGER.email(),
            assignee=rmt.support_manager,
            execution_time=today() + 86400 + 11 * 3600,  # tomorrow, 11:00,
            app_id=prospect.app_id,
            comment=u"Customer wanted to pay an order in the customer store, "
            "but didn't succeed because he did not link his creditcard.",
            notify_by_email=True)
        task.put()
def _job():
    order_numbers = list(OrderNumber.all())
    charge_numbers = list(ChargeNumber.all())
    invoice_numbers = list(InvoiceNumber.all())
    # Change parent from some OrderNumbers from RegioMangerTeam to LegalEntity.
    # Increase last_number for that legal entity when the parent was a team.
    to_delete = list()
    for ordernumber in order_numbers:
        if ordernumber.parent_key().kind() == RegioManagerTeam.kind():
            # Delete OrderNumber with parent RegioManagerTeam
            logging.warn(
                "Deleting OrderNumber Year %s Original last number: %s" %
                (ordernumber.key().name(), ordernumber.last_number))
            to_delete.append(ordernumber)

    for chargenumber in charge_numbers:
        if chargenumber.parent_key().kind() == RegioManagerTeam.kind():
            logging.warn(
                "Deleting ChargeNumber Year %s Original last number: %s" %
                (chargenumber.key().name(), chargenumber.last_number))
            to_delete.append(chargenumber)

    for invoicenumber in invoice_numbers:
        if invoicenumber.parent_key().kind() == RegioManagerTeam.kind():
            logging.warn(
                "Deleting InvoiceNumber Year %s Original last number: %s" %
                (invoicenumber.key().name(), invoicenumber.last_number))
            # Delete InvoiceNumber with parent RegioManagerTeam
            to_delete.append(invoicenumber)
    db.delete(to_delete)

    for invoice in Invoice.all().filter(
            'date >', 1460635200
            if not DEBUG else 1459870047):  # Thu, 14 Apr 2016 12:00:00 GMT

        def trans():
            new_invoice = Invoice(key_name=InvoiceNumber.next(
                LegalEntity.create_key(invoice.legal_entity_id)),
                                  parent=invoice.parent_key())
            logging.warn("Creating new Invoice %s" % new_invoice.key().name())
            new_invoice.date = invoice.date
            new_invoice.pdf = invoice.pdf
            new_invoice.amount = invoice.amount
            new_invoice.vat_pct = invoice.vat_pct
            new_invoice.total_amount = invoice.total_amount
            new_invoice.paid = invoice.paid
            new_invoice.paid_timestamp = invoice.paid_timestamp
            new_invoice.payment_type = invoice.payment_type
            new_invoice.operator = invoice.operator
            new_invoice.legal_entity_id = invoice.legal_entity_id
            new_invoice.put()
            invoice.deleted = True
            invoice.put()

        run_in_xg_transaction(trans)
Example #3
0
    def test_association_creation(self):
        self.set_datastore_hr_probability(1)
        apps = [a.app_id for a in App.all()]
        r = create_flex_service(email=u'*****@*****.**',
                                name=u"test",
                                address=u"Antwerpsesteenweg 19\n9080 Lochristi",
                                phone_number=u"+32 9 324 25 64",
                                languages=[u"en", u"nl"],
                                currency=u"€",
                                modules=[SolutionModule.CITY_APP, SolutionModule.BROADCAST, SolutionModule.ASK_QUESTION,
                                         SolutionModule.WHEN_WHERE],
                                broadcast_types=['News', 'test'],
                                apps=apps,
                                allow_redeploy=False,
                                organization_type=OrganizationType.CITY)
        # Create city customer
        shop_user = users.User(u'*****@*****.**') 
        customer_id = None
        vat = u''
        name = u'Town Lochristi'
        address1 = u'Dorp - West 52'
        address2 = u''
        zip_code = u'9080'
        city = u'Lochristi'
        country = u'BE'
        language = u'nl'
        organization_type = OrganizationType.CITY
        prospect_id = None
        city_customer = create_or_update_customer(shop_user, customer_id, vat, name, address1, address2, zip_code, city,
                                                  country, language, organization_type, prospect_id,
                                                  team_id=RegioManagerTeam.all().get().id)
        city_customer.service_email = city_customer.user_email = r.login
        city_customer.default_app_id = apps[0]
        city_customer.app_ids = apps
        city_customer.put()

        # Create city contact
        first_name = u'Firstname'
        last_name = u'Lastname'
        email_address = u'*****@*****.**'
        phone_number = u'+3293268806'

        create_contact(city_customer, first_name, last_name, email_address, phone_number)

        name = u'test-Test association'
        address1 = u'Antwerpsesteenweg 19'
        address2 = u''
        zip_code = u'9080'
        city = u'Lochristi'
        user_email = u'*****@*****.**'
        telephone = u'+32 9 324 25 64'
        language = u'nl'
        modules = [u'agenda', u'bulk_invite', u'static_content', u'ask_question', u'broadcast']
        broadcast_types = [u'Evenementen', u'Nieuws']
        set_current_user(users.User(r.login), set_google_user=False)
        output = rest_put_service(name, address1, address2, zip_code, city, user_email, telephone, language, modules,
                                 broadcast_types)
        self.assertTrue(output.success, output.errormsg)
        self.assertFalse(output.errormsg)
Example #4
0
def create_customer_with_service(city_customer,
                                 customer,
                                 service,
                                 name,
                                 address1,
                                 address2,
                                 zip_code,
                                 city,
                                 language,
                                 organization_type,
                                 vat,
                                 website=None,
                                 facebook_page=None,
                                 force=False):
    """Given a customer and a service, will create the customer, contact and order."""
    from shop.bizz import put_customer_with_service
    customer_id = customer.id if customer else None
    if not customer and organization_type not in city_customer.editable_organization_types:
        organization_type = city_customer.editable_organization_types[0]

    if city_customer.can_only_edit_organization_type(
            ServiceProfile.ORGANIZATION_TYPE_NON_PROFIT):
        product_code = Product.PRODUCT_SUBSCRIPTION_ASSOCIATION
    else:
        product_code = Product.PRODUCT_FREE_SUBSCRIPTION

    team = RegioManagerTeam.get_by_id(city_customer.team_id)
    if not team.legal_entity.is_mobicage:
        if product_code == Product.PRODUCT_SUBSCRIPTION_ASSOCIATION:
            from shop.products import create_sjup_product
            p = create_sjup_product(team.legal_entity_id,
                                    "%s." % team.legal_entity_id)
            p.put()
            product_code = p.code
        else:
            from shop.products import create_free_product
            p = create_free_product(team.legal_entity_id,
                                    "%s." % team.legal_entity_id)
            p.put()
            product_code = p.code

    return put_customer_with_service(service,
                                     name,
                                     address1,
                                     address2,
                                     zip_code,
                                     city,
                                     city_customer.country,
                                     language,
                                     organization_type,
                                     vat,
                                     city_customer.team_id,
                                     product_code,
                                     customer_id,
                                     website,
                                     facebook_page,
                                     force=force)
def set_default_legal_entity_to_teams():
    mobicage_legal_entity_id = get_mobicage_legal_entity().id
    to_put = list()
    for team in RegioManagerTeam.all():
        if not team.legal_entity_id:
            team.legal_entity_id = mobicage_legal_entity_id
        team.is_mobicage = team.name == 'Mobicage'
        to_put.append(team)
    db.put(to_put)
Example #6
0
def get_vat_pct(customer, team=None):
    team = team or RegioManagerTeam.get_by_id(customer.team_id)
    if team.id != customer.team_id:
        raise BusinessException(
            'Invalid team specified to get_vat_pct, got %d, expected %d' %
            (team.id, customer.team_id))
    if customer.should_pay_vat:
        return team.legal_entity.vat_percent
    return 0
Example #7
0
    def _create_customer_and_subscription_order(self, products):
        customer = create_or_update_customer(self.current_user,
                                             customer_id=None,
                                             vat=u'BE4863 456 123',
                                             name=u'Test customer',
                                             address1=u'',
                                             address2=None,
                                             zip_code=u'9080',
                                             city=u'Lochristi',
                                             country=u'BE',
                                             language=DEFAULT_LANGUAGE,
                                             organization_type=OrganizationType.PROFIT,
                                             prospect_id=None,
                                             team_id=RegioManagerTeam.all().get().id)

        contact = create_contact(customer.id, u'Bart', u'example', u'*****@*****.**', u'+32 9 324 25 64')
        items = self._create_items(customer, products)
        return self._create_order(customer, contact.id, items)
Example #8
0
def create_task_for_order(customer_team_id, prospect_id, order_number):
    team, prospect = db.get([
        RegioManagerTeam.create_key(customer_team_id),
        Prospect.create_key(prospect_id)
    ])
    azzert(team.support_manager,
           u'No support manager found for team %s' % team.name)
    comment = u'Customer placed a new order: %s' % (order_number)
    task = create_task(
        created_by=STORE_MANAGER.email(),
        prospect_or_key=prospect,
        app_id=prospect.app_id,
        status=ShopTask.STATUS_NEW,
        task_type=ShopTask.TYPE_SUPPORT_NEEDED,
        address=None,
        assignee=team.support_manager,
        comment=comment,
        execution_time=today() + 86400 + 11 * 3600,  # tomorrow at 11:00
        notify_by_email=True)
    task.put()
    broadcast_task_updates([team.support_manager])
    def _create_customer_and_subscription_order(self, products):
        customer = create_or_update_customer(
            self.current_user,
            customer_id=None,
            vat=u'BE4863 456 123',
            name=u'Test customer',
            address1=u'',
            address2=None,
            zip_code=u'9080',
            city=u'Lochristi',
            country=u'BE',
            language=DEFAULT_LANGUAGE,
            organization_type=OrganizationType.PROFIT,
            prospect_id=None,
            team_id=RegioManagerTeam.all().get().id)

        contact = create_contact(customer.id, u'Bart', u'example',
                                 u'*****@*****.**', u'+32 9 324 25 64')
        items = list()
        for x, product_info in enumerate(products):
            if isinstance(product_info, tuple):
                product_code, product_count = product_info
            else:
                product_code = product_info
                product_count = None

            product = Product.get_by_code(product_code)
            order_item = OrderItemTO()
            order_item.comment = product.default_comment(customer.language)
            order_item.count = product.default_count if product_count is None else product_count
            if product_code == u'MSUP' and product_count is None:
                order_item.count *= 2
            order_item.number = x
            order_item.product = product_code
            items.append(order_item)

        order = create_order(customer.id, contact.id, items)
        sign_order(customer.id, order.order_number,
                   'image/png,%s' % base64.b64encode(UNKNOWN_AVATAR))
        return db.get((order.key(), customer.key()))
    def trans():
        charge = None
        expired_subscription, customer = db.get([ExpiredSubscription.create_key(customer_id),
                                                       Customer.create_key(customer_id)])
        expired_subscription.status = status
        expired_subscription.status_updated_timestamp = now()

        if status == ExpiredSubscription.STATUS_WILL_LINK_CREDIT_CARD:
            # Create a task for regiomanager to check if the customer has linked his credit card after two weeks.
            # the ExpiredSubscription object from this customer will be cleaned up in recurrentbilling the day after he has linked it.
            to_put.append(expired_subscription)
            team, prospect = db.get([RegioManagerTeam.create_key(customer.team_id),
                                     Prospect.create_key(customer.prospect_id)])
            execution_time = now() + DAY * 14
            date_string = datetime.datetime.utcfromtimestamp(execution_time).strftime(u'%A %d %b %Y')
            comment = u'Check if the customer has linked his creditcard (for automatic subscription renewal).' \
                      u' If he hasn\'t linked it before %s, contact him again.' % date_string
            task = create_task(current_user.email(), prospect, team.support_manager, execution_time,
                               ShopTask.TYPE_CHECK_CREDIT_CARD, prospect.app_id, comment=comment)
            to_put.append(task)

        elif status == ExpiredSubscription.STATUS_EXTEND_SUBSCRIPTION:
            # Creates a new charge using the customer his subscription order.
            subscription_order, team = db.get([Order.create_key(customer.id, customer.subscription_order_number),
                                               RegioManagerTeam.create_key(customer.team_id)])
            extension_order_item_keys = list()
            order_items = list(OrderItem.list_by_order(subscription_order.key()))
            products_to_get = list()
            for item in order_items:
                products_to_get.append(Product.create_key(item.product_code))
            products = {p.code: p for p in Product.get(products_to_get)}
            # extend per year
            months = 12
            total_amount = 0
            for item in order_items:
                product = products[item.product_code]
                if product.is_subscription and item.price > 0:
                    total_amount += months * item.price
                elif not product.is_subscription and (product.is_subscription_discount or product.extra_subscription_months > 0):
                    total_amount += months * item.price
                elif product.is_subscription_extension:
                    total_amount += months * item.price
                    extension_order_item_keys.append(item.key())

            if total_amount <= 0:
                raise BusinessException('The created charge has a negative amount (%d)' % total_amount)
            next_charge_datetime = datetime.datetime.utcfromtimestamp(now()) + relativedelta(months=months)
            subscription_order.next_charge_date = get_epoch_from_datetime(next_charge_datetime)
            to_put.append(subscription_order)

            # reconnect all previously connected friends if the service was disabled in the past
            if customer.service_disabled_at != 0:
                deferred.defer(set_service_enabled, customer.id, _transactional=True)

            vat_pct = get_vat_pct(customer, team)
            charge = Charge(parent=subscription_order)
            charge.date = now()
            charge.type = Charge.TYPE_SUBSCRIPTION_EXTENSION
            charge.subscription_extension_length = months
            charge.subscription_extension_order_item_keys = extension_order_item_keys
            charge.amount = total_amount
            charge.vat_pct = vat_pct
            charge.vat = int(total_amount * vat_pct / 100)
            charge.total_amount = charge.amount + charge.vat
            charge.currency_code = team.legal_entity.currency_code
            to_put.append(charge)
            to_delete.append(expired_subscription)

        db.put(to_put)
        if to_delete:
            db.delete(to_delete)

        return charge
Example #11
0
def create_and_pay_news_order(service_user, news_item_id, order_items_to):
    """
    Creates an order, orderitems, charge and executes the charge. Should be executed in a transaction.
    Args:
        service_user (users.User)
        news_item_id (long)
        order_items_to (ist of OrderItemTO)

    Raises:
        NoCreditCardException
        ProductNotFoundException
    """
    @db.non_transactional
    def _get_customer():
        return get_customer(service_user)

    @db.non_transactional
    def _get_contact():
        return Contact.get_one(customer)

    customer = _get_customer()
    azzert(customer)
    contact = _get_contact()
    azzert(contact)
    if not customer.stripe_valid:
        raise NoCreditCardException(customer)
    extra_city_product_key = Product.create_key(Product.PRODUCT_EXTRA_CITY)
    news_product_key = Product.create_key(Product.PRODUCT_NEWS_PROMOTION)
    rmt_key = RegioManagerTeam.create_key(customer.team_id)
    extra_city_product, news_promotion_product, team = db.get(
        (extra_city_product_key, news_product_key, rmt_key))
    azzert(extra_city_product)
    azzert(news_promotion_product)
    azzert(team)
    new_order_key = Order.create_key(customer.id,
                                     OrderNumber.next(team.legal_entity_key))
    vat_pct = get_vat_pct(customer, team)

    total_amount = 0
    added_app_ids = []
    for order_item in order_items_to:
        if order_item.product == Product.PRODUCT_EXTRA_CITY:
            total_amount += extra_city_product.price * order_item.count
            added_app_ids.append(order_item.app_id)
            order_item.price = extra_city_product.price
        elif order_item.product == Product.PRODUCT_NEWS_PROMOTION:
            total_amount += news_promotion_product.price * order_item.count
            order_item.price = news_promotion_product.price
        else:
            raise BusinessException('Invalid product \'%s\'' %
                                    order_item.product)
    si = get_default_service_identity(users.User(customer.service_email))
    if added_app_ids:
        keys = [App.create_key(app_id) for app_id in added_app_ids]
        apps = db.get(keys)
        for app_id, app in zip(added_app_ids, apps):
            if not app:
                raise AppNotFoundException(app_id)
            if app_id in si.appIds:
                raise BusinessException('Customer %s already has app_id %s' %
                                        (customer.id, app_id))

    vat = int(round(vat_pct * total_amount / 100))
    total_amount_vat_incl = int(round(total_amount + vat))
    now_ = now()
    to_put = []
    order = Order(key=new_order_key,
                  date=now_,
                  amount=total_amount,
                  vat_pct=vat_pct,
                  vat=vat,
                  total_amount=total_amount_vat_incl,
                  contact_id=contact.id,
                  status=Order.STATUS_SIGNED,
                  is_subscription_order=False,
                  is_subscription_extension_order=False,
                  date_signed=now_,
                  manager=STORE_MANAGER,
                  team_id=team.id)
    to_put.append(order)
    azzert(order.total_amount >= 0)

    for item in order_items_to:
        order_item = OrderItem(parent=new_order_key,
                               number=item.number,
                               product_code=item.product,
                               count=item.count,
                               comment=item.comment,
                               price=item.price)
        order_item.app_id = item.app_id
        if order_item.product_code == Product.PRODUCT_NEWS_PROMOTION:
            order_item.news_item_id = news_item_id
        to_put.append(order_item)

    db.put(to_put)

    # Not sure if this is necessary
    deferred.defer(generate_and_put_order_pdf_and_send_mail,
                   customer,
                   new_order_key,
                   service_user,
                   _transactional=True)

    # No need for signing here, immediately create a charge.
    to_put = []
    charge = Charge(parent=new_order_key)
    charge.date = now()
    charge.type = Charge.TYPE_ORDER_DELIVERY
    charge.amount = order.amount
    charge.vat_pct = order.vat_pct
    charge.vat = order.vat
    charge.total_amount = order.total_amount
    charge.manager = order.manager
    charge.team_id = order.team_id
    charge.status = Charge.STATUS_PENDING
    charge.date_executed = now()
    charge.currency_code = team.legal_entity.currency_code
    to_put.append(charge)

    # Update the regiomanager statistics so these kind of orders show up in the monthly statistics
    deferred.defer(update_regiomanager_statistic,
                   gained_value=order.amount / 100,
                   manager=order.manager,
                   _transactional=True)

    # Update the customer service
    si.appIds.extend(added_app_ids)
    to_put.append(si)

    # Update the customer object so the newly added apps are added.
    customer.app_ids.extend(added_app_ids)
    customer.extra_apps_count += len(added_app_ids)
    to_put.append(customer)
    db.put(to_put)
    deferred.defer(re_index, si.user)

    # charge the credit card
    if charge.total_amount > 0:
        get_payed(customer.id, order, charge)
        server_settings = get_server_settings()
        send_to = server_settings.supportWorkers
        send_to.append(MC_DASHBOARD.email())
        channel_data = {
            'customer': customer.name,
            'no_manager': True,
            'amount': charge.amount / 100,
            'currency': charge.currency
        }
        channel.send_message(map(users.User, send_to),
                             'shop.monitoring.signed_order',
                             info=channel_data)
    else:
        charge.status = Charge.STATUS_EXECUTED
        charge.date_executed = now()
        charge.put()
    channel.send_message(service_user, 'common.billing.orders.update')
def job():
    default_team_id = RegioManagerTeam.get_mobicage().id
    run_job(_qry, [], _worker, [default_team_id])
Example #13
0
def create_reseller_invoice_for_legal_entity(legal_entity,
                                             start_date,
                                             end_date,
                                             do_send_email=True):
    """
    Args:
        legal_entity (LegalEntity) 
        start_date (long)
        end_date (long)
        do_send_email (bool)
    """
    if legal_entity.is_mobicage:
        # To avoid a composite index we don't filter on is_mobicage
        return
    solution_server_settings = get_solution_server_settings()
    from_email = solution_server_settings.shop_no_reply_email
    to_emails = solution_server_settings.shop_payment_admin_emails
    mobicage_legal_entity = get_mobicage_legal_entity()
    logging.info(
        'Exporting reseller invoices for legal entity %s(id %d) from %s(%s) to %s(%s)',
        legal_entity.name, legal_entity.id, start_date, time.ctime(start_date),
        end_date, time.ctime(end_date))
    invoices = list(Invoice.all().filter(
        'legal_entity_id',
        legal_entity.id).filter('paid_timestamp >', start_date).filter(
            'paid_timestamp <', end_date).filter('paid', True).filter(
                'payment_type IN',
                (Invoice.PAYMENT_MANUAL, Invoice.PAYMENT_MANUAL_AFTER)))
    start_time = time.strftime('%m/%d/%Y', time.gmtime(int(start_date)))
    end_time = time.strftime('%m/%d/%Y', time.gmtime(int(end_date)))
    if not invoices:
        message = 'No new invoices for reseller %s for period %s - %s' % (
            legal_entity.name, start_time, end_time)
        logging.info(message)
        if do_send_email:
            send_mail(from_email, to_emails, message, message)
        return
    items_per_customer = {}
    customers_to_get = set()
    products = {
        p.code: p
        for p in Product.list_by_legal_entity(legal_entity.id)
    }
    for invoice in invoices:
        # get all subscription order items
        order_items = list(OrderItem.list_by_order(invoice.order_key))
        for item in reversed(order_items):
            product = products[item.product_code]
            # We're only interested in subscription items
            if product.is_subscription or product.is_subscription_extension or product.is_subscription_discount:
                if invoice.customer_id not in items_per_customer:
                    items_per_customer[invoice.customer_id] = []
                    customers_to_get.add(
                        Customer.create_key(invoice.customer_id))
                items_per_customer[invoice.customer_id].append(item)
            else:
                order_items.remove(item)
    if not customers_to_get:
        message = 'No new invoices containing subscriptions for reseller %s for period %s - %s' % (
            legal_entity.name, start_time, end_time)
        logging.info(message)
        if do_send_email:
            send_mail(from_email, to_emails, message, message)
        return
    customers = {c.id: c for c in db.get(customers_to_get)}
    product_totals = {}
    for customer_id in items_per_customer:
        items = items_per_customer[customer_id]
        for item in items:
            if item.product_code not in product_totals:
                product_totals[item.product_code] = {
                    'count': 0,
                    'price': int(item.price * legal_entity.revenue_percent)
                }
            product_totals[item.product_code]['count'] += item.count
    total_amount = 0
    for product in product_totals:
        p = product_totals[product]
        price = p['count'] * p['price']
        p['total_price'] = format_currency(
            price / 100.,
            legal_entity.currency_code,
            locale=mobicage_legal_entity.country_code)
        total_amount += price
    total_amount_formatted = format_currency(
        total_amount / 100.,
        legal_entity.currency_code,
        locale=mobicage_legal_entity.country_code)
    vat_amount = total_amount / mobicage_legal_entity.vat_percent if mobicage_legal_entity.country_code == legal_entity.country_code else 0
    vat_amount_formatted = format_currency(
        vat_amount / 100.,
        legal_entity.currency_code,
        locale=mobicage_legal_entity.country_code)
    from_date = format_datetime(datetime.utcfromtimestamp(start_date),
                                locale=SHOP_DEFAULT_LANGUAGE,
                                format='dd/MM/yyyy HH:mm')
    until_date = format_datetime(datetime.utcfromtimestamp(end_date),
                                 locale=SHOP_DEFAULT_LANGUAGE,
                                 format='dd/MM/yyyy HH:mm')

    solution_server_settings = get_solution_server_settings()
    template_variables = {
        'products':
        products,
        'customers':
        customers,
        'invoices':
        invoices,
        'items_per_customer':
        items_per_customer,
        'product_totals':
        product_totals.items(),
        'mobicage_legal_entity':
        mobicage_legal_entity,
        'legal_entity':
        legal_entity,
        'language':
        SHOP_DEFAULT_LANGUAGE,
        'from_date':
        from_date,
        'until_date':
        until_date,
        'revenue_percent':
        legal_entity.revenue_percent,
        'vat_amount_formatted':
        vat_amount_formatted,
        'total_amount_formatted':
        total_amount_formatted,
        'logo_path':
        '../html/img/osa_white_en_250.jpg',
        'tos_link':
        '<a href="%s">%s</a>' %
        (solution_server_settings.shop_privacy_policy_url,
         solution_server_settings.shop_privacy_policy_url)
    }
    source_html = SHOP_JINJA_ENVIRONMENT.get_template(
        'invoice/reseller_invoice.html').render(template_variables)
    output_stream = StringIO()
    pisa.CreatePDF(src=source_html,
                   dest=output_stream,
                   path='%s/invoice' % SHOP_TEMPLATES_FOLDER)
    invoice_pdf_contents = output_stream.getvalue()
    output_stream.close()
    # Create an order, order items, charge and invoice.
    _now = now()
    customer = legal_entity.get_or_create_customer()
    mobicage_team = RegioManagerTeam.get_mobicage()

    def trans():
        to_put = list()
        order_number = OrderNumber.next(mobicage_legal_entity)
        order_key = db.Key.from_path(Order.kind(),
                                     order_number,
                                     parent=customer.key())
        order = Order(key=order_key)
        order.contact_id = legal_entity.contact_id
        order.date = _now
        order.vat_pct = mobicage_legal_entity.vat_percent if legal_entity.country_code == mobicage_legal_entity.country_code else 0
        order.amount = int(round(total_amount))
        order.vat = int(round(vat_amount))
        order.total_amount = int(round(total_amount + vat_amount))
        order.is_subscription_order = False
        order.is_subscription_extension_order = False
        order.team_id = mobicage_team.id
        order.manager = customer.manager
        order.status = Order.STATUS_SIGNED
        to_put.append(order)

        for i, (product_code, item) in enumerate(product_totals.iteritems()):
            order_item = OrderItem(parent=order_key)
            order_item.number = i + 1
            order_item.comment = products[product_code].default_comment(
                SHOP_DEFAULT_LANGUAGE)
            order_item.product_code = product_code
            order_item.count = item['count']
            order_item.price = item['price']
            to_put.append(order_item)

        charge_key = Charge.create_key(allocate_id(Charge), order_number,
                                       customer.id)
        charge = Charge(key=charge_key)
        charge.date = _now
        charge.type = Charge.TYPE_ORDER_DELIVERY
        charge.amount = order.amount
        charge.vat_pct = order.vat_pct
        charge.vat = order.vat
        charge.total_amount = order.total_amount
        charge.manager = order.manager
        charge.team_id = order.team_id
        charge.charge_number = ChargeNumber.next(mobicage_legal_entity)
        charge.currency_code = legal_entity.currency_code
        to_put.append(charge)

        invoice_number = InvoiceNumber.next(mobicage_legal_entity)
        invoice = Invoice(key_name=invoice_number,
                          parent=charge,
                          amount=charge.amount,
                          vat_pct=charge.vat_pct,
                          vat=charge.vat,
                          total_amount=charge.total_amount,
                          currency_code=legal_entity.currency_code,
                          date=_now,
                          payment_type=Invoice.PAYMENT_MANUAL_AFTER,
                          operator=charge.manager,
                          paid=False,
                          legal_entity_id=mobicage_legal_entity.id,
                          pdf=invoice_pdf_contents)
        charge.invoice_number = invoice_number
        to_put.append(invoice)
        put_and_invalidate_cache(*to_put)
        return order, charge, invoice

    order, charge, invoice = run_in_xg_transaction(trans)

    if do_send_email:
        serving_url = '%s/internal/shop/invoice/pdf?customer_id=%d&order_number=%s&charge_id=%d&invoice_number=%s' % (
            get_server_settings().baseUrl, customer.id, order.order_number,
            charge.id, invoice.invoice_number)
        subject = 'New reseller invoice for %s, %s - %s' % (
            legal_entity.name, start_time, end_time)
        body_text = 'A new invoice is available for reseller %s for period %s to %s here: %s' % (
            legal_entity.name, start_time, end_time, serving_url)

        send_mail(from_email, to_emails, subject, body_text)
Example #14
0
    def trans():
        customer_id = order_key.parent().id()
        order, customer = db.get([order_key, Customer.create_key(customer_id)])
        if not order.next_charge_date:
            logging.warning(
                'Not creating recurrent charge for order %s (%s: %s) because no next charge date is set',
                order.order_number, customer_id, customer.name)
            return None
        elif order.next_charge_date > today:
            # Scenario: this job fails today, tomorrow this job runs again and fails again
            # -> 2 jobs for the same order would create 2 charges when the bug is fixed
            logging.warning(
                'This order has already been charged this month, skipping... %s (%s: %s)',
                order.order_number, customer_id, customer.name)
            return None
        elif customer.subscription_cancel_pending_date:
            logging.info('Disabling service from customer %s (%d)',
                         customer.name, customer.id)
            try:
                cancel_order(customer, order.order_number)
            except OrderAlreadyCanceledException as exception:
                logging.info('Order %s already canceled, continuing...',
                             exception.order.order_number)

            set_service_disabled(customer, Customer.DISABLED_OTHER)
            cleanup_expired_subscription(customer)
            return None

        logging.info("Creating recurrent charge for order %s (%s: %s)",
                     order.order_number, customer_id, customer.name)
        subscription_extension_orders = list(
            Order.all().ancestor(customer).filter(
                "next_charge_date <",
                today).filter("is_subscription_order =", False).filter(
                    'is_subscription_extension_order =',
                    True).filter("status =",
                                 Order.STATUS_SIGNED))  # type: list[Order]
        subscription_extension_order_keys = [
            o.key() for o in subscription_extension_orders
        ]
        order_item_qry = OrderItem.all().ancestor(
            customer if subscription_extension_order_keys else order)

        subscription_extension_order_item_keys = []
        total_amount = 0
        subscription_length = 0
        current_date = datetime.datetime.utcnow()
        to_put = []
        for order_item in order_item_qry:  # type: OrderItem
            product = products[order_item.product_code]
            if order_item.order_number == order.order_number:
                if product.is_subscription:
                    subscription_length = order_item.count
                if product.is_subscription or product.is_subscription_discount or product.is_subscription_extension:
                    if product.charge_interval != 1:
                        last_charge_date = datetime.datetime.utcfromtimestamp(
                            order_item.last_charge_timestamp)
                        new_charge_date = last_charge_date + relativedelta(
                            months=product.charge_interval)
                        if new_charge_date < current_date:
                            logging.debug(
                                'new_charge_date %s < current_date %s, adding %s to total_amount',
                                new_charge_date, current_date,
                                order_item.price)
                            total_amount += order_item.price
                            order_item.last_charge_timestamp = now()
                            to_put.append(order_item)
                    else:
                        total_amount += order_item.price

            elif order_item.parent().key(
            ) in subscription_extension_order_keys:
                if product.is_subscription_extension:
                    total_amount += order_item.price
                    subscription_extension_order_item_keys.append(
                        order_item.key())
        if total_amount == 0:
            order.next_charge_date = Order.default_next_charge_date()
            order.put()
            logging.info(
                "Skipping, cannot calculate recurrent charge of 0 euros for order %s (%s: %s)",
                order.order_number, customer_id, customer.name)
            return None

        if subscription_length == 0:
            raise Exception('subscription_length is 0')

        if not (customer.stripe_id and
                customer.stripe_credit_card_id) and subscription_length != 1:
            logging.debug(
                'Tried to bill customer, but no credit card info was found')
            audit_log(
                customer.id,
                'Tried to bill customer, but no credit card info was found')
            # Log the customer as expired. If this has not been done before.
            expired_subscription_key = ExpiredSubscription.create_key(
                customer_id)
            if not ExpiredSubscription.get(expired_subscription_key):
                to_put.append(
                    ExpiredSubscription(
                        key=expired_subscription_key,
                        expiration_timestamp=order.next_charge_date))
                # Create a task for the support manager
                assignee = customer.manager and customer.manager.email()
                if customer.team_id is not None:
                    team = RegioManagerTeam.get_by_id(customer.team_id)
                    if team.support_manager:
                        assignee = team.support_manager
                if assignee:
                    if customer.prospect_id:
                        prospect = Prospect.get(
                            Prospect.create_key(customer.prospect_id))
                    else:
                        # We can only create tasks for prospects. So we must create a prospect if there was none.
                        prospect = create_prospect_from_customer(customer)
                        customer.prospect_id = prospect.id
                        to_put.append(customer)
                        to_put.append(prospect)
                    to_put.append(
                        create_task(
                            created_by=None,
                            prospect_or_key=prospect,
                            assignee=assignee,
                            execution_time=today + 11 * 3600,
                            task_type=ShopTask.TYPE_SUPPORT_NEEDED,
                            app_id=prospect.app_id,
                            status=ShopTask.STATUS_NEW,
                            comment=
                            u"Customer needs to be contacted for subscription renewal",
                            notify_by_email=True))
                put_and_invalidate_cache(*to_put)
            return None
        else:
            cleanup_expired_subscription(customer)

        @db.non_transactional  # prevent contention on entity group RegioManagerTeam
        def get_currency_code():
            return customer.team.legal_entity.currency_code

        charge = Charge(parent=order_key)
        charge.date = now()
        charge.type = Charge.TYPE_RECURRING_SUBSCRIPTION
        charge.subscription_extension_length = 1
        charge.subscription_extension_order_item_keys = subscription_extension_order_item_keys
        charge.currency_code = get_currency_code()
        charge.team_id = customer.team_id
        charge.amount = total_amount
        charge.vat_pct = order.vat_pct
        charge.vat = int(total_amount * order.vat_pct / 100)
        charge.total_amount = charge.amount + charge.vat
        to_put.append(charge)

        next_charge_datetime = datetime.datetime.utcfromtimestamp(
            order.next_charge_date) + relativedelta(months=1)
        next_charge_date_int = int(
            (next_charge_datetime -
             datetime.datetime.utcfromtimestamp(0)).total_seconds())
        order.next_charge_date = next_charge_date_int
        to_put.append(order)
        for extension_order in subscription_extension_orders:
            extension_order.next_charge_date = next_charge_date_int
            to_put.append(extension_order)

        put_and_invalidate_cache(*to_put)
        return charge
Example #15
0
    def trans():
        old_order, team = db.get(
            (old_order_key, RegioManagerTeam.create_key(customer.team_id)))

        if not old_order:
            return BoolReturnStatusTO.create(
                False,
                translate(
                    get_solution_settings(service_user).main_language,
                    SOLUTION_COMMON, u'cart_empty'), False)

        # Duplicate the order
        to_put = list()
        to_delete = list()
        properties = copy_model_properties(old_order)
        properties['status'] = Order.STATUS_SIGNED
        properties['date_signed'] = now()
        new_order_key = Order.create_key(
            customer.id, OrderNumber.next(team.legal_entity_key))
        new_order = Order(key=new_order_key, **properties)
        new_order.team_id = team.id
        to_delete.append(old_order)

        # duplicate all of the order items
        old_order_items = OrderItem.list_by_order(old_order_key)
        all_products = db.get([
            Product.create_key(item.product_code) for item in old_order_items
        ])
        is_subscription_extension_order = False
        for product in all_products:
            if product.is_subscription_extension:
                is_subscription_extension_order = True
                break
        new_order.is_subscription_extension_order = is_subscription_extension_order
        if is_subscription_extension_order:
            subscription_order = Order.get_by_order_number(
                customer.id, customer.subscription_order_number)
            new_order.next_charge_date = subscription_order.next_charge_date
        added_apps = list()
        should_create_shoptask = False
        for old_item in old_order_items:
            properties = copy_model_properties(old_item)
            new_item = OrderItem(parent=new_order_key, **properties)
            to_put.append(new_item)
            to_delete.append(old_item)
            if hasattr(old_item, 'app_id'):
                added_apps.append(old_item.app_id)
            else:
                should_create_shoptask = True
        to_put.append(new_order)
        db.put(to_put)
        db.delete(to_delete)

        deferred.defer(generate_and_put_order_pdf_and_send_mail,
                       customer,
                       new_order_key,
                       service_user,
                       _transactional=True)

        # No need for signing here, immediately create a charge.
        azzert(new_order.total_amount > 0)
        charge = Charge(parent=new_order_key)
        charge.date = now()
        charge.type = Charge.TYPE_ORDER_DELIVERY
        charge.amount = new_order.amount
        charge.vat_pct = new_order.vat_pct
        charge.vat = new_order.vat
        charge.total_amount = new_order.total_amount
        charge.manager = new_order.manager
        charge.team_id = new_order.team_id
        charge.status = Charge.STATUS_PENDING
        charge.date_executed = now()
        charge.currency_code = team.legal_entity.currency_code
        charge.put()

        # Update the regiomanager statistics so these kind of orders show up in the monthly statistics
        deferred.defer(update_regiomanager_statistic,
                       gained_value=new_order.amount / 100,
                       manager=new_order.manager,
                       _transactional=True)

        # Update the customer service
        si = get_default_service_identity(users.User(customer.service_email))
        si.appIds.extend(added_apps)
        si.put()
        deferred.defer(re_index, si.user, _transactional=True)

        # Update the customer object so the newly added apps are added.
        customer.app_ids.extend(added_apps)
        customer.extra_apps_count += len(added_apps)
        customer.put()

        get_payed(customer.id, new_order, charge)
        # charge the credit card
        channel.send_message(service_user, 'common.billing.orders.update')
        channel_data = {
            'customer': customer.name,
            'no_manager': True,
            'amount': charge.amount / 100,
            'currency': charge.currency
        }
        server_settings = get_server_settings()
        send_to = server_settings.supportWorkers
        send_to.append(MC_DASHBOARD.email())
        channel.send_message(map(users.User, send_to),
                             'shop.monitoring.signed_order',
                             info=channel_data)
        if should_create_shoptask:
            prospect_id = customer.prospect_id
            if prospect_id is None:
                prospect = create_prospect_from_customer(customer)
                prospect_id = prospect.id
            deferred.defer(create_task_for_order,
                           customer.team_id,
                           prospect_id,
                           new_order.order_number,
                           _transactional=True)
        return BoolReturnStatusTO.create(True, None)
Example #16
0
    def trans():
        to_put = list()
        customer_store_order_key = Order.create_key(
            customer.id, Order.CUSTOMER_STORE_ORDER_NUMBER)
        subscription_order_key = Order.create_key(
            customer.id, customer.subscription_order_number)
        team_key = RegioManagerTeam.create_key(customer.team_id)
        product_key = Product.create_key(item.code)

        if item.app_id is not MISSING:
            app_key = App.create_key(item.app_id)
            product, customer_store_order, sub_order, app, team = db.get([
                product_key, customer_store_order_key, subscription_order_key,
                app_key, team_key
            ])
            if sub_order.status != Order.STATUS_SIGNED:
                raise BusinessException(
                    translate(lang, SOLUTION_COMMON, u'no_unsigned_order'))
            # check if the provided app does exist
            azzert(app)
        else:
            product, customer_store_order, team = db.get(
                [product_key, customer_store_order_key, team_key])

        # Check if the item has a correct count.
        # Should never happen unless the user manually recreates the ajax request..
        azzert(
            not product.possible_counts
            or item.count in product.possible_counts
            or item.code == Product.PRODUCT_EXTRA_CITY,
            u'Invalid amount of items supplied')
        number = 0
        existing_order_items = list()
        vat_pct = get_vat_pct(customer, team)
        item_already_added = False
        if not customer_store_order:
            # create new order
            customer_store_order = Order(key=customer_store_order_key)
            customer_store_order.contact_id = contact.key().id()
            customer_store_order.date = now()
            customer_store_order.vat_pct = 0
            customer_store_order.amount = 0
            customer_store_order.vat = 0
            customer_store_order.vat_pct = vat_pct
            customer_store_order.total_amount = 0
            customer_store_order.is_subscription_order = False
            customer_store_order.manager = STORE_MANAGER
            customer_store_order.team_id = None
        else:
            order_items = OrderItem.list_by_order(customer_store_order.key())
            for i in order_items:
                number = i.number if i.number > number else number
                existing_order_items.append(i)
                # Check if this city isn't already in the possible pending order.
                if hasattr(i, 'app_id') and (i.app_id == item.app_id or
                                             item.app_id in customer.app_ids):
                    raise BusinessException(
                        translate(lang, SOLUTION_COMMON,
                                  u'item_already_added'))
                else:
                    # Check if there already is an orderitem with the same product code.
                    # If so, add the count of this new item to the existing item.
                    for it in order_items:
                        if it.product_code == item.code and it.product_code not in (
                                Product.PRODUCT_EXTRA_CITY,
                                Product.PRODUCT_NEWS_PROMOTION):
                            if (
                                    it.count + item.count
                            ) in product.possible_counts or not product.possible_counts:
                                it.count += item.count
                                item_already_added = True
                                to_put.append(it)
                                order_item = it
                            elif len(product.possible_counts) != 0:
                                raise BusinessException(
                                    translate(
                                        lang,
                                        SOLUTION_COMMON,
                                        u'cant_order_more_than_specified',
                                        allowed_items=max(
                                            product.possible_counts)))

        if item.app_id is not MISSING:
            remaining_length, _ = get_subscription_order_remaining_length(
                customer.id, customer.subscription_order_number)
            subscription_order_charge_date = format_date(
                datetime.datetime.utcfromtimestamp(sub_order.next_charge_date),
                locale=lang)
            total = remaining_length * product.price
        else:
            total = product.price * item.count
        vat = total * vat_pct / 100
        total_price = total + vat
        customer_store_order.amount += total
        customer_store_order.vat += vat
        azzert(customer_store_order.total_amount >= 0)
        customer_store_order.total_amount += total_price
        service_visible_in_translation = None
        if not item_already_added:
            order_item = OrderItem(parent=customer_store_order.key())
            order_item.number = number
            order_item.comment = product.default_comment(customer.language)
            order_item.product_code = product.code
            if item.app_id is not MISSING:
                order_item.count = remaining_length
                service_visible_in_translation = translate(
                    lang,
                    SOLUTION_COMMON,
                    'service_visible_in_app',
                    subscription_expiration_date=subscription_order_charge_date,
                    amount_of_months=remaining_length,
                    extra_city_price=product.price_in_euro,
                    app_name=app.name)
            else:
                order_item.count = item.count
            order_item.price = product.price

            if item.app_id is not MISSING:
                order_item.app_id = item.app_id
            to_put.append(order_item)
        to_put.append(customer_store_order)
        db.put(to_put)
        return order_item, service_visible_in_translation
Example #17
0
def add_new_prospect_from_discovery(user_details, steps):
    kwargs = dict()
    simple_step_ids = ('name', 'location-manual')
    for step in steps:
        if step['step_type'] != 'form_step':
            continue

        step_id = step['step_id'][len('message_'):]  # cut off the 'message_' prefix
        if step_id in simple_step_ids:
            if step['form_result'] and step['form_result']['result']:
                value = step['form_result']['result']['value']
            else:
                value = ''
            kwargs[step_id] = value
        else:
            if step_id == 'location':
                if step['form_result']:
                    kwargs['latitude'] = step['form_result']['result']['latitude']
                    kwargs['longitude'] = step['form_result']['result']['longitude']
    if 'location-manual' in kwargs:
        try:
            lat, lon, place_id, postal_code, address = address_to_coordinates(kwargs['location-manual'])
        except GeoCodeZeroResultsException:
            logging.warn('Could not reverse geocode for address %s, no results found', kwargs['location-manual'])
            return
    else:
        lat = kwargs['latitude']
        lon = kwargs['longitude']
        try:
            address, postal_code, place_id = coordinates_to_address(lat, lon)
        except GeoCodeZeroResultsException:
            logging.warn('Could not reverse geocode for coordinates %d %d, no results found', lat, lon)
            return
    name = string.capwords(kwargs['name'])

    app = ShopApp.find_by_postal_code(postal_code)
    azzert(app, 'App not found for postal code %s' % postal_code)
    team = RegioManagerTeam.get_by_app_id(app.app_id)
    assignee = team.support_manager
    azzert(assignee, 'No support manager found for team %s' % team.name)

    def trans():
        prospect = Prospect(key_name=place_id,
                            name=name,
                            app_id=app.app_id,
                            type=[],
                            categories=[u'unclassified'],
                            address=address,
                            geo_point=db.GeoPt(lat, lon),
                            assignee=assignee,
                            status=Prospect.STATUS_ADDED_BY_DISCOVERY,
                            phone=''
                            )
        task = create_task(assignee, Prospect.create_key(place_id), assignee, now() + 86400, ShopTask.TYPE_CALL,
                           app.app_id, ShopTask.STATUS_NEW, address, u'Created prospect via discovery', None, None)
        db.put([prospect, task])
        return prospect

    prospect = db.run_in_transaction(trans)
    re_index_prospect(prospect)
    broadcast_prospect_creation(None, prospect)
    broadcast_task_updates([assignee])
    logging.info('Created new prospect via prospect discovery: %s, %s' % (prospect.name, prospect.address))
Example #18
0
def export_invoices(year, month):
    start_date = datetime.date(year, month, 1)
    end_date = start_date + relativedelta(months=1)

    qry = Invoice.all() \
        .filter('date >=', get_epoch_from_datetime(start_date)) \
        .filter('date <', get_epoch_from_datetime(end_date))

    invoices = list()
    order_keys = set()
    all_products = dict(((p.code, p) for p in Product.all()))
    for invoice_model in qry:
        i = model_to_dict(invoice_model)
        order_key = invoice_model.parent_key().parent()
        i['invoice_number'] = invoice_model.invoice_number
        i['order_items'] = map(model_to_dict,
                               OrderItem.all().ancestor(order_key))
        if invoice_model.charge.is_recurrent:
            # only apply recurrent charges
            for order_item in reversed(i['order_items']):
                order_item[
                    'count'] = invoice_model.charge.subscription_extension_length or 1
                product = all_products[order_item['product_code']]
                if not (product.is_subscription_discount
                        or product.is_subscription
                        or product.is_subscription_extension):
                    i['order_items'].remove(order_item)

            # add the subscription extensions like XCTY
            if invoice_model.charge.subscription_extension_order_item_keys:
                known_extension_item_keys = [
                    item['_key'] for item in i['order_items']
                ]

                extension_order_items = db.get(
                    invoice_model.charge.subscription_extension_order_item_keys
                )
                for item in extension_order_items:
                    item.count = 1
                    if str(item.key()) not in known_extension_item_keys:
                        i['order_items'].append(model_to_dict(item))

        i['order_key'] = order_key
        i['currency'] = invoice_model.currency_code
        order_keys.add(order_key)
        invoices.append(i)

    orders = {o.key(): o for o in db.get(order_keys)}

    contact_keys = set()
    customer_keys = set()
    for i in invoices:
        order_model = orders[i['order_key']]
        del i['order_key']
        i['customer_key'] = order_model.customer_key
        i['contact_key'] = order_model.contact_key
        i['manager'] = None if not order_model.manager else order_model.manager.email(
        )
        customer_keys.add(order_model.customer_key)
        contact_keys.add(order_model.contact_key)

    del orders

    customer_and_contact_models = {
        m.key(): m
        for m in db.get(customer_keys.union(contact_keys))
    }

    # filter invoices for customers of resellers
    reseller_ids = [
        k.id() for k in LegalEntity.list_non_mobicage(keys_only=True)
    ]
    reseller_team_ids = [
        t.id for t in RegioManagerTeam.all().filter('legal_entity_id IN',
                                                    reseller_ids)
    ]

    for i in reversed(invoices):
        customer_model = customer_and_contact_models[i['customer_key']]
        if customer_model.team_id in reseller_team_ids:
            invoices.remove(i)
            continue
        del i['customer_key']
        i['customer'] = model_to_dict(customer_model)
        contact_model = customer_and_contact_models[i['contact_key']]
        del i['contact_key']
        i['contact'] = model_to_dict(contact_model)

    del customer_and_contact_models

    return sorted(invoices,
                  key=lambda i: int(i['invoice_number'].split('.')[-1]))