def _job(): products = {p.code: p for p in Product.all()} order_keys = set() for order_item in OrderItem.all(): if products[order_item.product_code].is_subscription_extension: order_keys.add(order_item.order_key) orders = db.get(order_keys) to_put = list() for order in orders: if not order.is_subscription_extension_order: order.is_subscription_extension_order = True customer = order.parent() subscription_order = Order.get_by_order_number(customer.id, customer.subscription_order_number) order.next_charge_date = subscription_order.next_charge_date to_put.append(order) for chunk in chunks(to_put, 200): db.put(chunk)
def _add_properties(): customers = Customer.all() to_put = list() for customer in customers: if customer.subscription_order_number: order_key = Order.create_key(customer.id, customer.subscription_order_number) order = Order.get(order_key) customer.creation_time = order.date customer.subscription_type = 0 if OrderItem.all( keys_only=True).ancestor(order_key).filter( 'product_code', 'MSSU').get() else 1 else: customer.creation_time = 0 # at this point it's not known when the customer was created if customer.service_email: service_user = users.User(email=customer.service_email) sln_settings = get_solution_settings(service_user) customer.has_loyalty = True if u'loyalty' in sln_settings.modules else False else: customer.has_loyalty = False to_put.append(customer) db.put(to_put)
def _replace_subscription_order(order_key, products, paying_subscription_product_codes): customer, old_order = db.get([order_key.parent(), order_key]) if not is_signup_enabled(customer.app_id): logging.debug( 'FREE_SUBSCRIPTIONS - Signup is not enabled for customer %s with app %s', customer.name, customer.app_id) return if customer.service_disabled_at != 0: logging.debug('FREE_SUBSCRIPTIONS - Customer %s is disabled', customer.name) return if old_order.status == Order.STATUS_SIGNED: order_items = list(OrderItem.all().ancestor(old_order)) ordered_product_codes = {i.product_code for i in order_items} if not ordered_product_codes.intersection( paying_subscription_product_codes): logging.debug( 'FREE_SUBSCRIPTIONS - Customer %s already had a FREE subscription: %s', customer.name, list(ordered_product_codes)) return logging.debug( 'FREE_SUBSCRIPTIONS - Creating new FREE order for customer %s', customer.name) new_order_items = [] for old_order_item in OrderItem.list_by_order(order_key): product = products[old_order_item.product_code] if product.is_subscription_extension: new_order_items.append(OrderItemTO.create(old_order_item)) if new_order_items: logging.debug( 'FREE_SUBSCRIPTIONS - Adding %s old order items: %s', len(new_order_items), serialize_complex_value(new_order_items, OrderItemTO, True)) free_item = OrderItemTO() free_item.comment = products[ Product.PRODUCT_FREE_SUBSCRIPTION].default_comment( customer.language) next_charge_date_time = datetime.datetime.utcfromtimestamp( old_order.next_charge_date) language = 'nl' if customer.language == 'nl' else 'en' next_charge_date = format_date(next_charge_date_time, locale=language) if language == 'nl': free_item.comment += u'\n\nEr zijn geen abonnementskosten meer! Uw abonnement is omgezet naar een gratis abonnement.' if new_order_items: free_item.comment += u'\n\nUw uitbreiding voor extra stad/steden is mee overgezet naar het nieuwe abonnement en zal, zoals bij het oude abonnement, op %s aangerekend worden.' % next_charge_date else: free_item.comment = u'There are no more subscription costs! Your subscription is changed to a free subscription' if new_order_items: free_item.comment += u'\n\nThe extension for extra cities is also transferred to the new subscription and will be charged at %s, just like you old subscription.' % next_charge_date free_item.count = 1 free_item.id = None free_item.number = 0 free_item.price = 0 free_item.product = Product.PRODUCT_FREE_SUBSCRIPTION free_item.service_visible_in = None new_order_items.append(free_item) new_order = create_order(customer, old_order.contact_id, new_order_items, replace=True, regio_manager_user=old_order.manager) new_order.next_charge_date = old_order.next_charge_date new_order.put() else: bizz_check( customer.subscription_order_number != old_order.order_number, 'Something is seriously wrong with customer %s (%s)!' % (customer.id, customer.name)) new_order = Order.get_by_order_number( customer.id, customer.subscription_order_number) if new_order.status == Order.STATUS_UNSIGNED and new_order.total_amount > 0: logging.debug('FREE_SUBSCRIPTIONS - Signing order %s for customer %s', new_order.order_number, customer.name) sign_order(customer.id, new_order.order_number, signature=u'', no_charge=True)
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]))
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