def add_to_cart(req, product_id, quantity=1): try: props = json.loads(req.GET['props']) except: props = [] if not props: props = [] product = Product.objects.get(id=product_id) order_item = OrderItem() order_item.product = product order_item.save() for prop in props: pps = list( ProductProp.objects.filter(title=prop['name'], product_id=product.id, value=prop['value'])) if len(pps): pp = pps[0] order_item.props.add(pp) cart = Cart(req) cart.add(order_item, product.price, quantity) return JsonResponse({'success': True, 'count': cart.count()})
def setUp(self): """ """ self.tax = TaxClass(name="20%", rate=Decimal('20.0')) self.tax.save() self.p1 = Product.objects.create(name="Product 1", slug="product-1") self.p2 = Product.objects.create(name="Product 2", slug="product-2") self.p1.save() self.p2.save() price1 = ProductPrice(product=self.p1, _unit_price=Decimal('10.0'), currency='CZK', tax_class=self.tax, tax_included=self.tax_included) price2 = ProductPrice(product=self.p2, _unit_price=Decimal('100.0'), currency='CZK', tax_class=self.tax, tax_included=self.tax_included) price1.save() price2.save() self.cart = Order() self.cart.save() item1 = OrderItem(order=self.cart, product=self.p1, quantity=1) item2 = OrderItem(order=self.cart, product=self.p2, quantity=1) item1.save() item2.save() self.cart.recalculate_totals() self.cart.save()
def remove_from_order(item_id): service_user = users.get_current_user() customer = get_customer(service_user) azzert(customer) customer_store_order_key = Order.create_key( customer.id, Order.CUSTOMER_STORE_ORDER_NUMBER) order_item_key = OrderItem.create_key(customer.id, Order.CUSTOMER_STORE_ORDER_NUMBER, item_id) order_item, order = db.get([order_item_key, customer_store_order_key]) if not order_item: logging.warn( "Customer %s tried to delete an already deleted item (%s)", service_user.email(), item_id) return RETURNSTATUS_TO_SUCCESS azzert(order) # Subtract the price from this product, then remove the product. vat = order_item.count * order_item.price * order.vat_pct / 100 total = order_item.count * order_item.price total_inc_vat = total + vat order.amount -= total order.total_amount -= total_inc_vat order.vat -= vat order_item.delete() order.put() return RETURNSTATUS_TO_SUCCESS
def create_order_items(cart, order): """ Create & save OrderItems from items in session cart """ for item in cart['items']: variation = ProdVariation.objects.get(sku=item['sku']) order_item = OrderItem( order=order, price=variation.price, product=variation.product, quantity=item['quantity'], size=variation.size, sku=variation.sku, width=variation.width ) order_item.save()
def get_order_items(): # get the order items for this customer from the latest order that isn't signed yet service_user = users.get_current_user() customer = get_customer(service_user) if not customer: return [] order_key = Order.create_key(customer.id, Order.CUSTOMER_STORE_ORDER_NUMBER) order = Order.get(order_key) if order: sln_settings = get_solution_settings(service_user) lang = sln_settings.main_language remaining_length, sub_order = 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) order_items = list(OrderItem.list_by_order(order_key)) order_items_updated = list() to_put = list() to_get = list( set([Product.create_key(o.product_code) for o in order_items] + [Product.create_key(Product.PRODUCT_EXTRA_CITY)])) products = {p.code: p for p in db.get(to_get)} # update the order items if necessary. for order_item in order_items: if products[ order_item. product_code].is_subscription_extension and order_item.count != remaining_length: order_item.count = remaining_length to_put.append(order_item) order_items_updated.append(order_item) if to_put: db.put(to_put) extra_city_price = format_price( products[Product.PRODUCT_EXTRA_CITY].price, sln_settings.currency) 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=extra_city_price, app_name='%(app_name)s') return [ OrderItemTO.create(i, service_visible_in_translation) for i in order_items_updated ] else: return []
def cancel_charge(customer_id, order_number, charge_id): """Cancels a charge so adjustments can be made to the order. Rolls back the next charge date of the subscription order. Args: customer_id: order_number: charge_id: Returns: None """ to_put = list() now_ = now() charge, order, customer = db.get([Charge.create_key(charge_id, order_number, customer_id), Order.create_key(customer_id, order_number), Customer.create_key(customer_id)]) charge.date_cancelled = now_ charge.status = Charge.STATUS_CANCELLED to_put.append(charge) order_items = list(OrderItem.list_by_order(order.key())) if order.is_subscription_order: months = 0 for item in order_items: product = item.product if product.is_subscription and product.price > 0: months += item.count if not product.is_subscription and product.extra_subscription_months > 0: months += product.extra_subscription_months if months > 0: next_charge_datetime = datetime.datetime.utcfromtimestamp(now()) - relativedelta(months=months) order.next_charge_date = get_epoch_from_datetime(next_charge_datetime) else: order.next_charge_date = Order.default_next_charge_date() else: extra_months = 0 for item in order_items: product = item.product if not product.is_subscription and product.extra_subscription_months > 0: extra_months += product.extra_subscription_months if extra_months > 0: sub_order = Order.get_by_order_number(customer_id, customer.subscription_order_number) next_charge_datetime = datetime.datetime.utcfromtimestamp(sub_order.next_charge_date) - relativedelta( months=extra_months) sub_order.next_charge_date = get_epoch_from_datetime(next_charge_datetime) to_put.append(sub_order) db.put(to_put)
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 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
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
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
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 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
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)
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(): 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)
def checkout(request): if request.method == 'GET': form = CheckForm() cart = request.session.get('cart') if cart is None: cart = [] for c in cart: size_str = c.get('size') tshirt_id = c.get('tshirt') size_obj = SizeVariant.objects.get(size=size_str, tshirt=tshirt_id) c['size'] = size_obj c['tshirt'] = size_obj.tshirt print(cart) return render(request, 'checkout.html', { "form": form, 'cart': cart }) else: # post request form = CheckForm(request.POST) user = None if request.user.is_authenticated: user = request.user if form.is_valid(): # payment cart = request.session.get('cart') if cart is None: cart = [] for c in cart: size_str = c.get('size') tshirt_id = c.get('tshirt') size_obj = SizeVariant.objects.get(size=size_str, tshirt=tshirt_id) c['size'] = size_obj c['tshirt'] = size_obj.tshirt shipping_address = form.cleaned_data.get('shipping_address') phone = form.cleaned_data.get('phone') payment_method = form.cleaned_data.get('payment_method') total = cal_total_payable_amount(cart) print(shipping_address, phone, payment_method, total) order = Order() order.shipping_address = shipping_address order.phone = phone order.payment_method = payment_method order.total = total order.order_status = "PENDING" order.user = user order.save() # saving order items for c in cart: order_item = OrderItem() order_item.order = order size = c.get('size') tshirt = c.get('tshirt') order_item.price = floor(size.price - (size.price * (tshirt.discount / 100))) order_item.quantity = c.get('quantity') order_item.size = size order_item.tshirt = tshirt order_item.save() buyer_name = f'{user.first_name} {user.last_name}' print(buyer_name) # crating payment response = API.payment_request_create( amount=order.total, purpose="Payment For Tshirts", send_email=True, buyer_name=f'{user.first_name} {user.last_name}', email=user.email, redirect_url="http://localhost:8000/validate_payment" ) payment_request_id = response ['payment_request']['id'] url = response['payment_request']['longurl'] payment = Payment() payment.order = order payment.payment_request_id= payment_request_id payment.save() return redirect(url) else: return redirect('/checkout/')
def create_order(request): data = copy.deepcopy(request.data) request_serializer = CreateNewOrderSerializer(data=data) request_serializer.is_valid(raise_exception=True) user = request.user person = Person.objects.get(user=user) try: # Create the initial order items = [] for order_item in data['order_items']: items.append({ "type": 'sku', "parent": order_item['parent'], "quantity": order_item['quantity'] }) stripe.api_key = settings.STRIPE_PRIVATE_KEY stripe_order = stripe.Order.create( currency='usd', items=items, shipping={ "name": '%s %s' % (user.first_name, user.last_name), "address": { "line1": person.address_line_1, "city": person.city, "state": person.state, "country": 'US', "postal_code": person.zipcode }, }, email=user.email) # Store the order data in our database order = Order(order_id=stripe_order.id, user=user, amount=stripe_order.amount, email=stripe_order.email, status=stripe_order.status, created=datetime.fromtimestamp(stripe_order.created), updated=datetime.fromtimestamp(stripe_order.updated)) order.currency = stripe_order.currency order.save() order_status = OrderStatusTransition(order=order, status=stripe_order.status, created=datetime.fromtimestamp( stripe_order.updated)) order_status.save() for item in stripe_order['items']: order_item = OrderItem(order=order, amount=item['amount'], description=item['description'], parent=item['parent'], quantity=item['quantity'], item_type=item['type']) order_item.currency = item.currency, order_item.save() updated_order = Order.objects.get(order_id=order.order_id) response_serializer = OrderSerializer(updated_order) return Response(response_serializer.data, status=status.HTTP_201_CREATED) except Exception as e: return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)
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)