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'})
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))
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))
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)
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)
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'})
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()
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))
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"))
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)
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)
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))
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()
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)
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()
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})