Esempio n. 1
0
def vote(request):
    # there's 'question_id' and 'up' in request.POST;
    # before doing anything, check if this user already voted on that question
    d = JsonParse(request.POST.get('data'))

    try:
        question_id = int(d.get('question_id'))
        v = int(d.get('up'))
    except:
        return JsonResponse({'status': 'error', 'message': _("Not enough data")})

    # get the question
    try:
        question = Question.objects.get(id=question_id)
    except Question.DoesNotExist:
        return JsonResponse({'status': 'error', 'message': _("Question does not exist")})

    # check if user has voted already
    if Vote.objects.filter(question=question, user=request.user).exists():
        return JsonResponse({'status': 'error', 'message': _("You already voted on this question")})

    # everything OK, add a Vote record and update Question
    Vote(user=request.user, created_by=request.user, question=question).save()

    if v:
        question.plus += 1
    else:
        question.minus += 1

    question.save()

    return JsonResponse({'status': 'ok'})
Esempio n. 2
0
def edit_product_(request, c, android=False):
    # sellers can edit product
    if not has_permission(request.user, c, 'product', 'edit'):
        return JsonError(_("You have no permission to edit products"))

    data = JsonParse(request.POST['data'])

    # see if product exists in database
    product_id = data['id']
    try:
        product = Product.objects.get(company=c, id=product_id)
    except:
        return JsonError(_("Product does not exist"))
    
    # validate data
    valid = validate_product(request.user, c, data)
    if not valid['status']:
        return JsonError(valid['message'])
    data = valid['data']
    
    # update product:
    product.name = data.get('name')
    product.category = data.get('category')
    product.unit_type = data.get('unit_type')
    product.code = data.get('code')
    product.shortcut = data.get('shortcut')
    product.description = data.get('description')
    product.private_notes = data.get('private_notes')
    # product.stock = data.get('stock')
    product.tax = data.get('tax')
    
    # update discounts
    product.update_discounts(request.user, data['discount_ids'])
    
    # image
    if data['change_image'] == True:
        if data.get('image'):  # new image is uploaded
            # create a file from the base64 data and save it to product.image
            if product.image:
                product.image.delete()
            # save a new image (conversion is done in validate_product)
            f = create_file_from_image(data['image'])
            product.image = f['file']
        else:  # delete the old image
            product.image.delete()
    
    # category
    if data['category']:
        product.category = data['category']

    # price has to be updated separately
    product.price = product.update_price(Price, request.user, data['price'])
    # if data.get('purchase_price'):
    #     product.price = product.update_price(PurchasePrice, request.user, data['purchase_price'])

    product.updated_by = request.user
    product.save()

    return JsonOk(extra=product_to_dict(request.user, c, product, android))
Esempio n. 3
0
def create_product_(request, c, android=False):
    # sellers can add product
    if not has_permission(request.user, c, 'product', 'edit'):
        return JsonError(_("You have no permission to add products"))

    data = JsonParse(request.POST['data'])
    
    # validate data
    valid = validate_product(request.user, c, data)
    if not valid['status']:
        return JsonError(valid['message'])
    data = valid['data']
    
    # save product:
    product = Product(
        company=c,
        created_by=request.user,
        category=data.get('category'),
        name=data.get('name'),
        code=data.get('code'),
        shortcut=data.get('shortcut'),
        description=data.get('description'),
        private_notes=data.get('private_notes'),
        stock=data.get('stock'),
        tax=data.get('tax'),
    )
    product.save()
    
    # update discounts
    product.update_discounts(request.user, data['discount_ids'])
    
    # prices have to be updated separately
    price = product.update_price(Price, request.user, data['price']) # purchase price
    if not price:
        product.delete()
        return JsonError(_("Error while setting purchase price"))


    #if data.get('purchase_price'):
    #    price = product.update_price(PurchasePrice, request.user, data['purchase_price'])
    #    if not price:
    #        product.delete()
    #        return JsonError(_("Error while setting sell price"))
    
    # add image, if it's there
    if data['change_image']:
        if 'image' in data:
            f = create_file_from_image(data['image'])
            product.image = f['file']
            product.save()
    
    return JsonOk(extra=product_to_dict(request.user, c, product, android))
Esempio n. 4
0
File: bill.py Progetto: rokj/sellout
def print_bill(request, company_id):
    try:
        c = Company.objects.get(id=company_id)
    except Company.DoesNotExist:
        return JsonError(_("Company does not exist"))

    # check permissions: needs to be guest
    if not has_permission(request.user, c, 'bill', 'view'):
        return JsonError(_("You have no permission to view bills."))

    data = JsonParse(request.POST['data'])

    bill_id = data.get('id')

    if bill_id:
        try:
            b = Bill.objects.get(company=c, serial=bill_id)
            bill = create_printable_bill(request.user, c, b, esc=True)
        except Bill.DoesNotExist:
            return JsonError(_("Bill does not exist"))


    return JsonOk(extra=bill)
Esempio n. 5
0
def mobile_list_discounts(request, company_id):
    try:
        c = Company.objects.get(id=company_id)
    except Company.DoesNotExist:
        return JsonError(_("Company does not exist"))

    # check permissions: needs to be guest
    if not has_permission(request.user, c, 'discount', 'view'):
        return JsonError(_("view discounts"))

    discounts = Discount.objects.filter(company__id=c.id)

    results_display = False

    data = JsonParse(request.POST['data'])

    # show the filter form
    if request.method == 'POST':

        if data.get('search'):
            discounts = discounts.filter(description__icontains=data['search']) | \
                        discounts.filter(code__icontains=data['search'])

        # start_date
        if data.get('start_date'):
            # parse date first
            start_date = data.get('start_date')
            start = dtm.date(year=start_date[0], month=start_date[1],
                             day=start_date[2])

            discounts = discounts.filter(start_date__gte=start)

        # end_date
        if data.get('end_date'):
            end_date = data.get('end_date')
            end = dtm.date(year=end_date[0], month=end_date[1],
                             day=end_date[2])

            discounts = discounts.filter(end_date__lse=end)

        # active
        if data.get('active') is not None:
            discounts = discounts.filter(active=data['active'])

        results_display = True  # search results are being displayed


    r = []
    for d in discounts:
        r.append(discount_to_dict(request.user, c, d, android=True))

    return JsonOk(extra=r)
Esempio n. 6
0
def accept(request):
    # receive (comment) id in request.POST and mark that comment as an answer
    d = JsonParse(request.POST.get('data'))

    try:
        comment_id = d.get('id')
    except:
        return JsonResponse({'status': 'error', 'message': _("No comment specified")})

    # get the comment
    try:
        comment = Comment.objects.get(id=comment_id)
    except Comment.DoesNotExist:
        return JsonResponse({'status': 'error', 'message': _("Comment does not exist")})

    # check if an accepted answer exists already
    if Comment.objects.filter(question__id=comment.question.id, is_answer=True).exists():
        return JsonResponse({'status': 'error', 'message': _("This question already has an answer")})

    # everything OK, mark this comment as answer
    comment.is_answer = True
    comment.save()

    return JsonResponse({'status': 'ok'})
Esempio n. 7
0
def edit_permission(request, company):
    """ receive a JSON with fields: permission_id, permission, pin """
    try:
        c = Company.objects.get(url_name=company)
    except Company.DoesNotExist:
        return JsonError(_("Company does not exist"))

    # get data
    try:
        d = JsonParse(request.POST.get('data'))
        if not d:
            raise KeyError
    except (ValueError, AttributeError, TypeError, KeyError):
        return JsonError(_("No data in request"))

    # check for permission:
    if not has_permission(request.user, c, 'user', 'edit'):
        return JsonError(_("You have no permission to edit users"))

    # get the permission
    try:
        permission = Permission.objects.get(id=int(d.get('permission_id')), company=c)
    except (ValueError, Permission.DoesNotExist):
        return JsonError(_("This user does not exist"))

    # check the data
    if d.get('permission') not in g.PERMISSION_TYPES:
        return JsonError(_("This permission type does not exist"))

    if len(d.get('pin')) != g.PIN_LENGTH:
        return JsonError(_("Wrong pin length."))

    # check if not degrading the last admin in the group
    if Permission.objects.filter(company=c, permission='admin').exclude(id=permission.id).count() == 0:
        # there would be no admins left in this company; do not allow changing permission
        if d.get('permission') != 'admin':
            return JsonError(_("You cannot change permission of the last admin of this company."))

    # everything seems to be OK, update PIN
    if not permission.create_pin(int(d.get('pin'))):
        return JsonError(_("This PIN has already been assigned to a user from this company. "
                           "Please choose a different one."))

    permission.permission = d.get('permission')
    permission.save()

    # ok!
    return JsonOk()
Esempio n. 8
0
def edit_company(request, company_id):
    try:
        c = Company.objects.get(id=company_id)
    except Company.DoesNotExist:
        return JsonError(_("Company does not exist"))

    if not has_permission(request.user, c, 'company', 'edit'):
        return JsonError(message=_("edit company details"))

    data = JsonParse(request.POST['data'])

    validate_data = validate_company(request.user, c, data)
    if validate_data['status']:
        data = validate_data['data']
    else:
        return JsonError(message=validate_data['message'])

    c.name = data.get('name')
    c.url_name = data.get('url_name')
    c.email = data.get('email')
    c.postcode = data.get('postcode')
    c.city = data.get('city')
    c.state = data.get('state')
    c.phone = data.get('phone')
    c.vat_no = data.get('vat_no')
    c.website = data.get('website')
    c.notes = data.get('notes')
    c.tax_payer = data.get('tax_payer')


    if data.get('change_color_logo'):
        if data.get('color_logo'):
            d = {'image': data.get('color_logo')}
            save_color_image(c, d)
        else:
            save_color_image(c, {})

    if data.get('change_monochrome_logo'):
        if data.get('monochrome_logo'):
            d = {'image': data.get('monochrome_logo')}
            save_monochrome_image(c, d)
        else:
            save_monochrome_image(c, {})

    c.save()

    return JsonOk(extra=company_to_dict(request.user, c, android=True))
Esempio n. 9
0
def mass_edit(request, company):
    try:
        c = Company.objects.get(url_name=company)
    except Company.DoesNotExist:
        return JsonError(_("Company does not exist"))

    # there must be stuff in request.POST
    data = JsonParse(request.POST.get('data'))

    if not data:
        return JsonError(_("No data in request"))

    # get product ids from data
    if len(data.get('products')) == 0:
        return JsonError(_("No products selected"))

    products = Product.objects.filter(company=c, id__in=data.get('products'))
    action = data.get('action')

    # decide what to do for each action
    if action == 'set-tax':
        # get the tax with given id and put it on all products
        try:
            tax = Tax.objects.get(company=c, id=data.get('id'))
        except (Tax.DoesNotExist, ValueError, TypeError):
            return JsonError(_("Tax does not exist"))

        for p in products:
            p.tax = tax
            p.save()

        return JsonOk()

    elif action == 'add-discount':
        # go through each product and add a discount
        try:
            discount = Discount.objects.get(company=c, id=data.get('id'))
        except (Discount.DoesNotExist, ValueError, TypeError):
            return JsonError(_("Discount does not exist or is not valid"))

        # add this discount to all products in list
        for p in products:
            p.add_discount(request.user, discount)

        return JsonOk()

    elif action == 'remove-discount':
        try:
            discount = Discount.objects.get(company=c, id=data.get('id'))
        except (Discount.DoesNotExist, ValueError, TypeError):
            return JsonError(_("Discount does not exist or is not valid"))

        # remove this discount from all products in list
        for p in products:
            p.remove_discount(discount)

        return JsonOk()

    elif action == 'clear-discounts':
        # there is no discounts, just remove all discounts from all products in the list
        for p in products:
            ProductDiscount.objects.filter(product=p).delete()

        return JsonOk()

    else:
        return JsonError(_("Unsupported mass edit action"))
Esempio n. 10
0
def search_products_(request, c, android=False):
    # permissions: needs to be guest
    if not has_permission(request.user, c, 'product', 'view'):
        return JsonError(_("You have no permission to view products"))
    
    # get all products from this company and filter them by entered criteria
    products = Product.objects.filter(company=c)
    
    criteria = JsonParse(request.POST.get('data'))
    
    # filter by: ("advanced" values in criteria dict)
    # name_filter
    if criteria.get('name_filter'):
        filter_by_name = True
        products = products.filter(name__icontains=criteria.get('name_filter'))
    else:
        filter_by_name = False

    # product_code_filter
    if criteria.get('product_code_filter'):
        filter_by_product_code = True
        products = products.filter(code__icontains=criteria.get('product_code_filter'))
    else:
        filter_by_product_code = False
    
    # shortcut_filter
    if criteria.get('shortcut_filter'):
        filter_by_shortcut = True
        products = products.filter(shortcut__icontains=criteria.get('shortcut_filter'))
    else:
        filter_by_shortcut = False
    
    # notes_filter
    if criteria.get('notes_filter'):
        filter_by_notes = True
        products = products.filter(private_notes__icontains=criteria.get('notes_filter'))
    else:
        filter_by_notes = False
        
    # description_filter
    if criteria.get('description_filter'):
        filter_by_description = True
        products = products.filter(description__icontains=criteria.get('description_filter'))
    else:
        filter_by_description = False
        
    # category_filter
    if criteria.get('category_filter'):
        filter_by_category = True
        products = products.filter(category__id__in=get_subcategories(int(criteria.get('category_filter')), data=[]))
    else:
        filter_by_category = False
        
    # tax_filter
    if criteria.get('tax_filter') and criteria.get('tax_filter').isdigit():
        #filter_by_tax = True
        products = products.filter(tax_id=int(criteria.get('tax_filter')))
    else:
        pass
        #filter_by_tax = False
    
    # price_filter
    if criteria.get('price_filter'):
        try:
            products = products.filter(
                pk__in=Price.objects.filter(
                    unit_price=decimal.Decimal(
                        criteria.get('price_filter'))).order_by('-datetime_updated')[:1])
            #filter_by_price = True
        except Price.DoesNotExist:
            pass
            #filter_by_price = False
    else:
        pass
        #filter_by_price = False

    # discount
    if criteria.get('discount_filter'):
        #filter_by_discount = True
        products = products.filter(discounts__code=criteria.get('discount_filter'))
    else:
        pass
        #filter_by_discount = False

    # general filter: search all fields that have not been searched yet 
    general_filter = criteria.get('general_filter')
    #g_products = Product.objects.none()
    if general_filter:
        general_filter = general_filter.split(' ')
        for w in general_filter:
            if w == '':
                continue

            # search categories, product_code, shortcut, name, description, notes,
            # but only if it wasn't entered in the "advanced" filter
            # assemble the Q() filter
            f = Q()
            if not filter_by_name:
                f = f | Q(name__icontains=w)
            if not filter_by_product_code:
                f = f | Q(code__icontains=w)
            if not filter_by_shortcut:
                f = f | Q(shortcut__icontains=w)
            if not filter_by_notes:
                f = f | Q(private_notes__icontains=w)
            if not filter_by_description:
                f = f | Q(description__icontains=w)
            if not filter_by_category:
                # get the categories that match this string and search by their subcategories also
                tmpcat = Category.objects.filter(name__icontains=w)
                for t in tmpcat:
                    f = f | Q(category__id__in=get_subcategories(t.id, data=[]))

            if f:
                products = products.filter(f)

            # omit search by tax, price, discount

    products = products.distinct().order_by('name')[:g.SEARCH_RESULTS['products']]
    
    # return serialized products
    ps = []
    for p in products:
        ps.append(product_to_dict(request.user, c, p, android=android))

    return JsonResponse(ps, safe=False)
Esempio n. 11
0
File: bill.py Progetto: rokj/sellout
def list_bills(request, company_id):
    try:
        c = Company.objects.get(id=company_id)
    except Company.DoesNotExist:
        return JsonError(_("Company does not exist"))

    # check permissions: needs to be guest
    if not has_permission(request.user, c, 'bill', 'view'):
        return JsonError(_("You have no permission to view bills."))

    N = 10  # if no search was made, display last N bills (below)
    searched = False

    data = JsonParse(request.POST['data'])

    if data.get('search'):
        # decide which way to order the results
        # this is the fake switch statement that is missing in python for no obvious reason
        ordering = {
            'id': 'serial',
            'date': 'timestamp',
            'amount': 'total'
        }
        order = ordering.get(data.get('sort_by'))
        if data.get('sort_order') == 'desc':
            order = '-' + order

        bills = Bill.objects.filter(company=c, payment__status=PAID).order_by(order)

        # filter by whatever is in the form:
        # issue date: from
        issued_from = data.get('issued_from')
        if issued_from:
            t = dtm.date(year=issued_from[0], month=issued_from[1],
                                 day=issued_from[2])
            bills = bills.filter(timestamp__gte=t)

        # issue date: to
        issued_to = data.get('issued_to')
        if issued_to:
            t = dtm.date(year=issued_to[0], month=issued_to[1],
                                 day=issued_to[2])
            bills = bills.filter(timestamp__lte=t)

        # item:
        t = data.get('item_code')
        if t:
            ids = [i.id for i in BillItem.objects.only('bill_id').filter(code__icontains=t)]

            # find all bills that include item that contains this code
            bills = bills.filter(id__in=ids)

        # contact
        t = data.get('contact')
        if t:
            bills = bills.filter(contact__first_name__icontains=t) | \
                    bills.filter(contact__last_name__icontains=t) | \
                    bills.filter(contact__company_name__icontains=t)


        # bill number
        t = data.get('id')
        if t:
            bills = bills.filter(serial=t)

        # amount: from
        t = data.get('amount_from')
        if t:
            bills = bills.filter(total__gte=t)

        # amount: to
        t = data.get('amount_to')
        if t:
            bills = bills.filter(total__lte=t)

        # user
        t = data.get('user_name')
        if t:
            bills = bills.filter(user_name__icontains=t)

        page = data.get('page')
        searched = True
    else:
        bills = Bill.objects.filter(company=c, payment__status=PAID).order_by('-timestamp')[:N]

    # format all bills manually
    bills = [bill_to_dict(request.user, c, b) for b in bills]

    return JsonOk(extra=bills)
Esempio n. 12
0
def quick_contacts(request, company):
    """
        creates contact on the fly (while creating bill on the terminal)
        contact data is in request.POST
    """
    try:
        c = Company.objects.get(url_name=company)
    except Company.DoesNotExist:
        return JsonError(_("Company does not exist."))

    # permissions
    if not has_permission(request.user, c, 'contact', 'edit'):
        return JsonError(_("You have no permission to add contacts"))

    contact = JsonParse(request.POST.get('data'))

    if not contact:
        return JsonError(_("No data in request"))

    r = validate_contact(request.user, c, contact)
    if not r['status']:
        return JsonError(r['message'])

    contact = r['data']

    if int(contact.get('id')) == -1:
        # it's a new contact: use .get() and forget about different types
        try:
            obj = Contact(
                created_by=request.user,
                company=c,

                type=contact.get('type'),
                company_name=contact.get('company_name'),
                first_name=contact.get('first_name'),
                last_name=contact.get('last_name'),
                sex=contact.get('sex'),
                date_of_birth=contact.get('date_of_birth'),
                street_address=contact.get('street_address'),
                postcode=contact.get('postcode'),
                city=contact.get('city'),
                state=contact.get('state'),
                country=contact.get('country'),
                email=contact.get('email'),
                phone=contact.get('phone'),
                vat=contact.get('vat')
            )

            obj.save()
        except Exception, e:
            return JsonResponse(_("Saving contact failed") + ": " + str(e))
Esempio n. 13
0
File: bill.py Progetto: rokj/sellout
def finish_bill_(request, c, android=False):
    # this should be only called from web, when paying with cash or credit card

    # permissions
    if not has_permission(request.user, c, "bill", "edit"):
        return JsonError(_("You have no permission to edit bills"))

    # data must contain: bill_id, status, payment_type, payment_reference
    d = JsonParse(request.POST.get("data"))

    if not d or not d.get("bill_id"):
        return JsonError(_("No data in request"))

    # bill...
    try:
        bill = Bill.objects.get(company=c, id=int(d.get("bill_id")))
    except (ValueError, TypeError, Bill.DoesNotExist):
        return JsonError(_("No bill found"))

    # check status: if 'Paid', set payment type and reference;
    # if 'Canceled', just update status
    if d.get("status") == g.PAID:
        # check payment type
        payment_type = d.get("payment_type")

        if payment_type not in g.PAYMENT_TYPE_VALUES:
            return JsonError(_("Payment type does not exist"))

        bill.status = g.PAID

        if payment_type == g.CASH or payment_type == g.CREDIT_CARD:
            bill.payment.type = payment_type
            # payment reference: if paid with bitcoin - btc address, if paid with cash, cash amount given
            # tole bols, da gre v payment_info, oz. bo kar moglo it, k zdej se je transaction_reference spremenil
            # (hehe spremenil, a stekas?:) ... se je spremenil v btc_transaction_reference in paypal_transaction_reference
            # bill.payment.transaction_reference = d.get('payment_reference')
    else:
        bill.status = g.CANCELED
        bill.stockify()

    bill.payment.save()
    bill.save()

    # if print is requested, return html, otherwise the 'ok' response
    if d.get("print"):
        if android:
            return JsonResponse(
                {
                    "status": "ok",
                    "bill_payment": payment_to_dict(request.user, c, bill.payment),
                    "print": esc_format(request.user, c, bill, bill.register.receipt_format, esc_commands=True),
                }
            )
        else:
            return JsonResponse(
                {
                    "status": "ok",
                    # 'print': esc_format(request.user, c, bill, bill.register.receipt_format, esc_commands=True),
                    "bill": create_bill_html(request.user, c, bill),
                }
            )

    return JsonOk()
Esempio n. 14
0
File: bill.py Progetto: rokj/sellout
def create_bill_(request, c):
    def item_error(message, product):
        return JsonError(message + " " + _("(Item" + ": ") + product.name + ")")

    # check permissions
    if not has_permission(request.user, c, "bill", "edit"):
        return JsonError(_("You have no permission to create bills"))

    # get data
    data = JsonParse(request.POST.get("data"))
    if not data:
        return JsonError(_("No data received"))

    # see if we're updating an existing bill
    existing_bill = None
    try:
        existing_bill = Bill.objects.get(company=c, id=int(data.get("id")))
        if existing_bill.status == g.PAID:
            return JsonError(_("This bill has already been paid, editing is not possible"))
    except (ValueError, TypeError):
        pass
    except Bill.DoesNotExist:
        pass

    # current company (that will be fixed on this bill forever):
    # save a FK to BillCompany; the last company is the current one
    bill_company = BillCompany.objects.filter(company=c).order_by("-datetime_created")[0]

    # current register: get BillRegister with the same id as current one
    try:
        bill_registers = BillRegister.objects.filter(register__id=int(data.get("register_id")))
        if len(bill_registers) > 0:
            bill_register = bill_registers[0]
        else:
            raise Register.DoesNotExist
    except (TypeError, ValueError, Register.DoesNotExist):
        return JsonError(_("Invalid register specified."))

    # current contact: get BillContact with the same id as the requested contact
    if data.get("contact"):
        try:
            bill_contacts = BillContact.objects.get(contact__id=int(data.get("contact").get("id"))).order_by(
                "datetime_created"
            )
            if len(bill_contacts) > 0:
                bill_contact = bill_contacts[0]
            else:
                raise Contact.DoesNotExist
        except (Contact.DoesNotExist, ValueError, TypeError):
            return JsonError(_("Invalid contact"))
    else:
        bill_contact = None

    # save all validated stuff in bill to a dictionary and insert into database at the end
    # prepare data for insert
    bill = {
        "company": c,
        "issuer": bill_company,
        "register": bill_register,
        "contact": bill_contact,
        "user_id": request.user.id,
        "user_name": str(request.user),
        "notes": data.get("notes", "")[: max_field_length(Bill, "notes")],
        "type": g.CASH,
        "status": g.WAITING,
        "items": [],
        "currency": get_company_value(request.user, c, "pos_currency"),
        # numbers...
        "base": Decimal(0),
        "discount": Decimal(0),
        "tax": Decimal(0),
        "total": Decimal(0),
        "created_by": request.user,
    }

    # timestamp
    try:
        # timestamp: send in an array of number:
        # [year, month, day, hour, minute, second]
        tn = [int(n) for n in data.get("timestamp")]
        bill["timestamp"] = dtm(year=tn[0], month=tn[1], day=tn[2], hour=tn[3], minute=tn[4], second=tn[5])

    except (ValueError, TypeError):
        return JsonError(_("Invalid timestamp"))

    r = parse_decimal(request.user, c, data.get("total"))
    if not r["success"] or r["number"] <= Decimal("0"):
        return JsonError(_("Invalid grand total value"))
    else:
        bill["total"] = r["number"]

    # validate items
    for i in data.get("items"):
        # get product
        try:
            product = Product.objects.get(company=c, id=int(i.get("product_id")))
        except Product.DoesNotExist:
            return JsonError(_("Product with this id does not exist") + " (id=" + i.get("product_id") + ")")

        # parse quantity
        r = parse_decimal(request.user, c, i.get("quantity"), g.DECIMAL["quantity_digits"])
        if not r["success"]:
            return item_error(_("Invalid quantity value"), product)
        else:
            if r["number"] <= Decimal("0"):
                return item_error(_("Cannot add an item with zero or negative quantity"), product)
        quantity = r["number"]

        # remove from stock; TODO: check negative quantities (?)
        # actually we leave negative quantities as they are or
        # when stock is empty, we leave it at 0

        product.destockify(quantity)
        product.save()

        item = {
            "created_by": request.user,
            "code": product.code,
            "shortcut": product.shortcut,
            "name": product.name,
            "description": product.description,
            "private_notes": product.private_notes,
            "unit_type": product.get_unit_type_display(),  # ! display, not the 'code'
            "stock": product.stock,
            # 'bill':  not now, after bill is saved
            "product_id": product.id,
            "bill_notes": i.get("bill_notes"),
            "discounts": [],  # validated discounts (FK in database)
            # prices: will be calculated when discounts are ready
            "base": None,
            "quantity": None,
            "tax_rate": None,
            "batch": None,
            "discount": None,
            "net": None,
            "tax": None,
            "total": None,
        }

        bill["items"].append(item)

        for d in i["discounts"]:
            # check:
            # discount id: if it's -1, it's a unique discount on this item;
            #              if it's anything else, the discount must belong to this company
            #              and must be active and enabled
            d_id = int(d.get("id"))
            if d_id != -1:
                try:
                    dbd = Discount.objects.get(id=d_id, company=c)

                    if not dbd.is_active:
                        return item_error(_("The discount is not active"), product)
                except Discount.DoesNotExist:
                    return item_error(_("Chosen discount does not exist or is not valid"), product)

            # amount: parse number and check that percentage does not exceed 100%
            r = parse_decimal(request.user, c, d.get("amount"))
            if not r["success"]:
                return item_error(_("Invalid discount amount"), product)
            else:
                d_amount = r["number"]
                if d_amount < Decimal(0) or (d.get("type") == "Relative" and d_amount > Decimal(100)):
                    return item_error(_("Invalid discount amount"), product)

            # save data to bill
            discount = {
                "id": d_id,
                "code": d.get("code"),
                "description": d.get("description"),
                "type": d.get("type"),
                "amount": d_amount,
            }
            item["discounts"].append(discount)

        # save this item's prices to item's dictionary (will go into database later)
        try:
            item["base"] = parse_decimal_exc(request.user, c, i.get("base"), message=_("Invalid base price"))
            item["quantity"] = parse_decimal_exc(request.user, c, i.get("quantity"), message=_("Invalid quantity"))
            item["tax_rate"] = parse_decimal_exc(request.user, c, i.get("tax_rate"), message=_("Invalid tax rate"))
            item["batch"] = parse_decimal_exc(request.user, c, i.get("batch"), message=_("Invalid batch price"))
            item["discount"] = parse_decimal_exc(
                request.user, c, i.get("discount"), message=_("Invalid discount amount")
            )
            item["net"] = parse_decimal_exc(request.user, c, i.get("net"), message=_("Invalid net price"))
            item["tax"] = parse_decimal_exc(request.user, c, i.get("tax"), message=_("Invalid tax amount"))
            item["total"] = parse_decimal_exc(request.user, c, i.get("total"), message=_("Invalid total"))

            bill["base"] += item["batch"]
            bill["discount"] += item["discount"]
            bill["tax"] += item["tax"]
        except ValueError as e:
            return item_error(e.message, product)

    # at this point, everything is fine, insert into database
    if existing_bill:
        existing_bill.delete()

    bill_payment = Payment(
        type=g.CASH,
        total=bill["total"],
        currency=get_company_value(request.user, c, "pos_currency"),
        transaction_datetime=datetime.utcnow(),
        status=g.WAITING,
        created_by=request.user,
    )
    bill_payment.save()

    # create a new bill
    db_bill = Bill(
        created_by=request.user,
        company=c,  # current company, FK to Company object
        issuer=bill["issuer"],  # fixed company details at this moment, FK to BillCompany object
        user_id=bill["user_id"],  # id of user that created this bill, just an integer, not a FK
        user_name=bill["user_name"],  # copied user name in case that user gets 'fired'
        register=bill["register"],  # current settings of the register this bill was created on
        contact=bill["contact"],  # FK on BillContact, copy of the Contact object
        notes=bill["notes"],
        # timestamp=dtm.utcnow().replace(tzinfo=timezone(get_company_value(request.user, c, 'pos_timezone'))),
        timestamp=bill["timestamp"],
        payment=bill_payment,
        base=bill["base"],
        discount=bill["discount"],
        tax=bill["tax"],
    )
    db_bill.save()

    # create new items
    for item in bill["items"]:
        db_item = BillItem(
            created_by=item["created_by"],
            code=item["code"],
            shortcut=item["shortcut"],
            name=item["name"],
            description=item["description"],
            private_notes=item["private_notes"],
            unit_type=item["unit_type"],
            bill=db_bill,
            bill_notes=item["bill_notes"],
            product_id=item["product_id"],
            quantity=item["quantity"],
            base=item["base"],
            tax_rate=item["tax_rate"],
            batch=item["batch"],
            discount=item["discount"],
            net=item["net"],
            tax=item["tax"],
            total=item["total"],
        )
        db_item.save()

        # save discounts for this item
        for discount in item["discounts"]:
            db_discount = BillItemDiscount(
                created_by=request.user,
                bill_item=db_item,
                description=discount["description"],
                code=discount["code"],
                type=discount["type"],
                amount=discount["amount"],
            )
            db_discount.save()

    db_bill.save()

    d = {"bill": bill_to_dict(request.user, c, db_bill)}

    return JsonOk(extra=d)
Esempio n. 15
0
File: bill.py Progetto: rokj/sellout
def send_invoice_(request, c):

    data = JsonParse(request.POST.get("data"))

    # there should be bill_id in request.POST
    try:
        bill_id = int(data.get("bill_id"))
        bill = Bill.objects.get(company=c, id=bill_id)
    except (Bill.DoesNotExist, ValueError, TypeError):
        return JsonError(_("Bill does not exist or data is invalid"))

    if bill.company == c and has_permission(request.user, c, "bill", "edit"):
        company_paypal_address = get_company_value(request.user, c, "pos_payment_paypal_address")
        if company_paypal_address == "":
            company_paypal_address = c.email

        if bill.status == g.PAID:
            return JsonResponse({"status": "error", "message": "bill_payment_already_paid"})

        merchant_info = {
            "email": company_paypal_address,
            "address": {"line1": c.street, "city": c.city, "country_code": c.country, "state": "XX"},
        }

        if c.name and c.name != "":
            merchant_info["business_name"] = c.name

        if c.phone and c.phone != "":
            merchant_info["phone"] = c.phone

        if c.website and c.website != "":
            merchant_info["website"] = c.website

        if c.postcode and c.postcode != "":
            merchant_info["address"]["postal_code"] = c.postcode

        if c.vat_no and c.vat_no != "":
            merchant_info["tax_id"] = c.vat_no

        customer_email = data.get("customer_email")

        try:
            validate_email(customer_email)
        except ValidationError:
            return JsonResponse({"status": "error", "message": "invalid_customer_email"})

        billing_info = [{"email": customer_email}]

        shipping_info = None
        items = []

        bill_datetime_format = g.DATE_FORMATS[get_company_value(request.user, c, "pos_date_format")]["python"]
        bill_datetime = bill.timestamp.strftime(bill_datetime_format) + " UTC"

        currency = get_company_value(request.user, c, "pos_currency")

        bill_items = BillItem.objects.filter(bill=bill)
        for bi in bill_items:
            try:
                product = Product.objects.get(id=bi.product_id)
                item_data = {
                    "name": product.name,
                    "quantity": bi.quantity.quantize(Decimal(".001"), rounding=ROUND_UP),
                    "unit_price": {"currency": currency, "value": bi.base.quantize(Decimal(".01"), rounding=ROUND_UP)},
                    "tax": {
                        "name": product.tax.name,
                        "percent": bi.tax_rate.quantize(Decimal(".001"), rounding=ROUND_UP),
                    },
                    "date": bill_datetime,
                }

                if product.description and product.description != "":
                    item_data["description"] = product.description

                if bi.discount and bi.discount is not None:
                    item_data["discount"] = bi.discount

                items.append(item_data)

            except Product.DoesNotExist:
                pass

        paypal = Paypal()

        if not paypal.create_invoice(
            invoice_id=bill.serial,
            merchant_info=merchant_info,
            billing_info=billing_info,
            shipping_info=shipping_info,
            items=items,
            invoice_date=bill_datetime,
        ):
            return JsonResponse({"status": "error", "message": "could_not_create_invoice"})

        payment = bill.payment
        payment.paypal_transaction_reference = paypal.response["id"]
        payment.save()

        if not paypal.send_invoice():
            return JsonResponse({"status": "error", "message": "could_not_send_invoice"})

    else:
        return JsonResponse({"status": "error", "message": "trying_to_compromise"})

    return JsonOk()
Esempio n. 16
0
def url_name_suggestions(request):
    # there's a 'name' in request:
    # take it and return a list of a few company url suggestions
    suggestions = []
    
    try:  # get name from sent data
        name = JsonParse(request.POST.get('data'))['name']
    except:
        return JsonResponse({'suggestions':[]})
    
    # 0. "lowercaseize"
    name = name.lower()
    
    # 1. "asciify"
    s = unidecode.unidecode(name)
    
    # 2. remove forbidden characters (everything but alphanumeric and dash) ("alphanumerify")
    s = re.sub(r'[^\w-]', ' ', s).strip()
    
    # first suggestion: full name - also remove duplicate -'s
    suggestions.append(unique_url_name(re.sub(r' +', '-', s)))
    
    # 2. remove one-character words ("unonecharacterify")
    # regex: one character followed by a space at the beginning OR
    # space followed by a character followed by a space OR
    # space followed by a character at the end
    s = re.sub(r'(^. )|(( ).(?= ))|( .$)', ' ', s)
    
    # 3. suggestions:
    # first word, then first and second, then ..., up to g.MISC['company_url_length'] chars
    max_len = g.MISC['company_url_length']
    words = s.split()
    
    for w in range(1, len(words)+1):
        s = ''
        for i in range(w):
            s += '-' + words[i]
            
        s = s[1:]  # cut off the first '-'
        if len(s) >= max_len:
            break
        
        suggestions.append(unique_url_name(s))
    
    # only first characters of every word (a.k.a. acronym)
    s = ''
    for w in words:
        s += w[0]
    suggestions.append(unique_url_name(s))

    # 4. remove possible inapropriate suggestions
    valid = []
    for s in suggestions:
        if check_url_name(s):
            valid.append(s)
    
    # 5. remove duplicates
    valid = list(set(valid))
    
    # 6. sort by length
    valid.sort(key=len)
    suggestions = valid
    del valid
    
    # 3a. add a random string to suggestions
    suggestions.append(unique_url_name(get_random_string(length=5).lower()))
    
    # pass on to the page
    return JsonResponse({'suggestions':suggestions})