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 xls_import(filename, company, user): status = { 'success': True, 'error_messages': [], 'info_messages': [], } def err(message, product_name=None, row=None, column=None): status['success'] = False status['error_messages'].append({'name': product_name, 'message': message, 'row': row, 'column': column}) def info(message, product_name=None, row=None, column=None): status['info_messages'].append({'name': product_name, 'message': message, 'row': row, 'column': column}) try: data = xlrd.open_workbook(filename) book = data.sheet_by_index(0) except: err(_("Opening the file failed")) raise XlsImportError(status) def value(ir, ic, product_name=None, check_col_len=None): # returns cell value at specified row/column, formatted as text #if book.cell_type(ir, ic) != xlrd.XL_CELL_TEXT: # this is obviously not working since nothing is formatted as text at all # info(_("Cell value is not formatted as text"), product_name, ir, ic) v = unicode(book.cell_value(ir, ic)).strip() if check_col_len: # if there's a maximum length of field l = max_field_length(Product, check_col_len) - 1 if l: return v[-l:] return v # or don't truncate it at all nrows = book.nrows ncols = book.ncols # exact number of columns required: 12 if ncols < 12: err(_("Invalid number of columns, 12 required") + " (this file: " + str(ncols) + ")", None, None) raise XlsImportError(status) # a collection of all valid data; # if everything validates successfully, this will be inserted into database valid_products = [] for irow in range(1, nrows): # the first row contains titles, start with the second # Name # check if a product with that name exists already icol = 0 cell = value(irow, icol, check_col_len='name') name = cell # Description # doesn't need checking icol = 1 cell = value(irow, icol, product_name=name) description = cell # Code icol = 2 cell = value(irow, icol, product_name=name, check_col_len='code') code = cell if Product.objects.filter(company=company, code=code).exists(): err(_("A product with this name exists already"), name, irow, icol) # Tax (number only, check if tax exists in database) icol = 3 cell = value(irow, icol, product_name=name) tax = None tax_amount = decimal.Decimal(1) try: tax_amount = decimal.Decimal(cell) tax = Tax.objects.get(company=company, amount=tax_amount) except Tax.DoesNotExist: err(_("Tax with this amount does not exist"), name, irow, icol) except (decimal.InvalidOperation, TypeError): err(_("Wrong number format for tax"), name) # Category (match by name or set no category to a product) icol = 4 cell = value(irow, icol, product_name=name) if Category.objects.filter(company=company, name=cell).count() > 0: # if there are multiple categories with the same name, take the first by id # this should be the parent category = Category.objects.filter(company=company, name=cell).order_by('id')[0] else: category = None info(_("Category not found, none assigned"), name, irow, icol) # Stock icol = 5 cell = value(irow, icol, product_name=name) stock = None try: stock = decimal.Decimal(cell) except (decimal.InvalidOperation, TypeError): err(_("Invalid number format for stock"), name, irow, icol) # Unit (anything that doesn't match the unit types list defaults to 'Piece') icol = 6 cell = value(irow, icol, product_name=name) if cell not in g.UNIT_CODES: unit_type = g.UNIT_CODES[0] # take a default info(_("No unit type matched, default taken"), name, irow, icol) else: unit_type = cell # Purchase price icol = 7 cell = value(irow, icol, product_name=name) purchase_price = None try: purchase_price = decimal.Decimal(cell) except (decimal.InvalidOperation, TypeError): err(_("Invalid number format for purchase price"), name, irow, icol) # Sell price without tax icol = 8 cell = value(irow, icol, product_name=name) try: price_without_tax = decimal.Decimal(cell) except (decimal.InvalidOperation, TypeError): price_without_tax = None # checking of this after parsing price with tax # Sell price with tax icol = 9 cell = value(irow, icol, product_name=name) try: price_with_tax = decimal.Decimal(cell) except (decimal.InvalidOperation, TypeError): price_with_tax = None if price_without_tax is None and price_with_tax is None: err(_("No prices set or their number format is not valid"), name, irow, icol) # calculate prices if price_with_tax and price_without_tax is None: price_without_tax = price_with_tax / (decimal.Decimal(1) + (tax_amount / decimal.Decimal(100))) # Shortcut icol = 10 cell = value(irow, icol, product_name=name, check_col_len='shortcut') shortcut = cell # Private notes icol = 11 cell = value(irow, icol, product_name=name) notes = cell # if there was no error, save all data for later use # if there was an error, don't even bother, the data won't be used anyway if status['success']: valid_products.append({ 'company': company, # these are required for Product.save() 'created_by': user, 'name': name, 'description': description, 'code': code, 'tax': tax, 'category': category, 'stock': stock, 'unit_type': unit_type, 'shortcut': shortcut, 'private_notes': notes, 'purchase_price': purchase_price, # these must not be in **kwargs for Product.save() 'price_without_tax': price_without_tax, }) # all products have been validated; # if there was no error, start inserting stuff into database; # keep all in the same transaction if not status['success']: raise XlsImportError(status) try: with transaction.atomic(): for p in valid_products: # save product: take prices out, then use **kwargs price_without_tax = p['price_without_tax'] del p['price_without_tax'] purchase_price = p['purchase_price'] del p['purchase_price'] product = Product(**p) product.save() # save prices if not product.update_price(Price, user, price_without_tax): err(_("Updating price failed"), product_name=p['name']) raise Exception("Updating price failed") # # if not product.update_price(PurchasePrice, user, purchase_price): # err(_("Updating purchase price failed"), product_name=p['name']) # raise Exception("Updating purchase price failed") # that's it return status except IntegrityError as ie: err(_("Error while saving to database"), ie.message, None, None) raise XlsImportError(status)