def stats(request, company): c = Company.objects.get(url_name=company) # permission? if not has_permission(request.user, c, 'stats', 'view'): return no_permission_view(request, c, _("You have no permission to view stats")) # recent earnings: all bills from today/yesterday/this week/this month, # their income and profit def bill_earnings(start_date=None, end_date=None): billset = Bill.objects.filter(company=c, payment__status=PAID) if start_date: billset = billset.filter(timestamp__gte=start_date) if end_date: billset = billset.filter(timestamp__lt=end_date) if billset.count() == 0: return { 'income': format_number(request.user, c, Decimal(0)), 'profit': format_number(request.user, c, Decimal(0)), } income = billset.aggregate(Sum('payment__total'))['payment__total__sum'] return { 'income': format_number(request.user, c, income), 'profit': format_number(request.user, c, income - billset.aggregate(Sum('base'))['base__sum'] - billset.aggregate(Sum('discount'))['discount__sum']) } today = dtm.datetime.utcnow().replace(tzinfo=timezone(get_company_value(request.user, c, 'pos_timezone'))) today = today.replace(hour=0, minute=0, second=0, microsecond=0) yesterday = today - dtm.timedelta(days=1) week_start = today - dtm.timedelta(days=today.weekday()) month_start = today.replace(day=1) # get custom dates from form, if they are present earnings_from = None earnings_to = None if request.method == "GET": r = parse_date(request.user, c, request.GET.get('earnings_from')) if not r['success']: earnings_from = None else: earnings_from = r['date'] r = parse_date(request.user, c, request.GET.get('earnings_to')) if not r['success']: earnings_to = None else: earnings_to = r['date'] if earnings_from and earnings_to and earnings_from > earnings_to: earnings_from = None earnings_to = None if earnings_from and earnings_to: custom_earnings = bill_earnings(start_date=earnings_from, end_date=earnings_to) else: custom_earnings = None earnings = { 'today': bill_earnings(start_date=today), 'yesterday': bill_earnings(start_date=yesterday, end_date=today), 'week': bill_earnings(start_date=week_start), 'month': bill_earnings(start_date=month_start), 'custom': custom_earnings, } # top-selling products: # today/yesterday/this week/this/month/overall TOP_PRODUCTS_LEN = 10 def top_products(start_date=None, end_date=None): itemset = BillItem.objects.filter(bill__company=c, bill__payment__status=PAID) if start_date: itemset = itemset.filter(bill__timestamp__gte=start_date) if end_date: itemset = itemset.filter(bill__timestamp__lt=end_date) itemset = itemset.values('name', 'code')\ .annotate(sold_quantity=Sum('quantity'))\ .order_by('-sold_quantity')[:TOP_PRODUCTS_LEN] # make sure the list is always exactly TOP_PRODUCTS_LEN long itemset = list(itemset) itemset += [None for t in range(TOP_PRODUCTS_LEN - len(itemset))] return itemset # custom date limits from form products_from = None products_to = None if request.method == "GET": r = parse_date(request.user, c, request.GET.get('products_from')) if not r['success']: products_from = None else: products_from = r['date'] r = parse_date(request.user, c, request.GET.get('products_to')) if not r['success']: products_to = None else: products_to = r['date'] if products_from and products_to and products_from > products_to: products_from = None products_to = None if products_from and products_to: custom_products = top_products(start_date=products_from, end_date=products_to) else: custom_products = [None for x in range(TOP_PRODUCTS_LEN)] products_data = { 'all_time': top_products(), 'yesterday': top_products(start_date=yesterday, end_date=today), 'week': top_products(start_date=week_start), 'month': top_products(start_date=month_start), 'custom': custom_products, } # convert the products from dict of lists to a simple list of rows for the template products = [] for i in range(TOP_PRODUCTS_LEN): if not products_data['all_time'][i]: break products.append({ 'all_time': products_data['all_time'][i], 'yesterday': products_data['yesterday'][i], 'week': products_data['week'][i], 'month': products_data['month'][i], 'custom': products_data['custom'][i], }) context = { 'company': c, 'earnings': earnings, 'earnings_from': format_date(request.user, c, earnings_from), 'earnings_to': format_date(request.user, c, earnings_to), 'products': products, 'products_from': format_date(request.user, c, products_from), 'products_to': format_date(request.user, c, products_to), 'title': _("Stats"), 'site_title': g.SITE_TITLE, 'date_format_js': get_date_format(request.user, c, 'js') } return render(request, 'pos/manage/stats.html', context)
def validate_contact(user, company, data): # data format (*-required data): # type* # company_name* (only if Company) # first_name* (only if Individual) # last_name* (only if Individual) # date_of_birth - list of discount ids (checked in create/edit_product) # street_address # postcode # city # country # state # email # phone # vat def err(msg): # the value that is returned if anything goes wrong return {'status': False, 'data': None, 'message': msg} # return: # status: True if validation passed, else False # data: 'cleaned' data if validation succeeded, else False # message: error message or empty if validation succeeded if 'type' not in data: return err(_("No type specified")) if data['type'] not in [x[0] for x in g.CONTACT_TYPES]: return err(_("Wrong contact type")) # check credentials for Individual if data['type'] == 'Individual': # first name: check length (mandatory) if not data.get('first_name'): return err(_("No first name")) elif len(data['first_name']) > max_field_length(Contact, 'first_name'): return err(_("First name too long")) # last name: check length (mandatory) if not data.get('last_name'): return err(_("No last name")) elif len(data['last_name']) > max_field_length(Contact, 'last_name'): return err(_("Last name too long")) # sex: must be in g.SEXES if 'sex' not in data and data['sex'] not in [x[0] for x in g.SEXES]: return err(_("Wrong sex")) # date of birth: parse date if 'date_of_birth' in data and len(data['date_of_birth']) > 0: r = parse_date(user, company, data['date_of_birth']) if not r['success']: return err(_("Wrong format of date of birth")) else: data['date_of_birth'] = r['date'] else: data['date_of_birth'] = None # check credentials for company else: if not data.get('company_name'): return err(_("No company name")) if len(data['company_name']) > max_field_length(Contact, 'company_name'): return err(_("Company name too long")) # one shalt not save u'' into date field. data['date_of_birth'] = None # common fields: # email is not required if 'email' in data: if len(data['email']) > max_field_length(Contact, 'email'): return err(_("Email address too long")) if 0 < len(data['email']) < 6: # there's something entered, but nothing useful return err(_("Email address too short")) # validate email with regex: # ^[\w\d._+%]+ a string with any number of characters, numbers, and ._+% signs # @[\w\d.-]{2,} an @ sign followed by domain name of at least 2 characters long (can contain . and -) # \.\w{2,4}$' domain (2-4 alphabetic characters) m = re.search('([\w.-]+)@([\w.-]+)', data['email']) if not m or not m.group() or data['email'] not in m.group(): return err(_("Invalid email address")) else: data['email'] = None # country: check for correct code if 'country' in data: if data['country'] not in country_by_code: return err(_("Country does not exist")) # other, non-mandatory fields: check length only def check_length(d, l): if d: if len(d) > l: return False else: return True else: return True # street_address if not check_length(data.get('street_address'), max_field_length(Contact, 'street_address')): return err(_("Street address too long")) # postcode if not check_length(data.get('postcode'), max_field_length(Contact, 'postcode')): return err(_("Post code too long")) # city if not check_length(data.get('city'), max_field_length(Contact, 'city')): return err(_("City name too long")) # state if not check_length(data.get('state'), max_field_length(Contact, 'state')): return err(_("State name too long")) # phone if not check_length(data.get('phone'), max_field_length(Contact, 'phone')): return err(_("Phone number too long")) # vat if not check_length(data.get('vat'), max_field_length(Contact, 'vat')): return err(_("VAT number too long")) # everything OK return {'status': True, 'data': data, 'message': None}