def save_color_image(c, data): if 'image' in data: # read the new image and upload it color_logo = import_color_image(data.get('image'), g.IMAGE_DIMENSIONS['color_logo'], 'aspect') if not color_logo: return JsonError(_("No file sent")) if c.color_logo.name: # the logo exists already, delete it try: os.remove(c.color_logo.path) except (OSError, ValueError): pass f = create_file_from_image(color_logo) c.color_logo.save(f['name'], f['file'], save=False) c.save() return JsonResponse({'status': 'ok', 'logo_url': c.color_logo.url}) else: # there is no image, remove the existing one try: os.remove(c.color_logo.path) c.color_logo.delete() c.save() except (OSError, ValueError): pass return JsonOk()
def validate_product(user, company, data): # data format (*-validation needed): # id # name* # price - numeric value* # unit type # discounts - list of discount ids (checked in create/edit_product) # image # category - id (checked in create/edit_product) # code* # shortcut* # description # private notes # tax* # stock* def r(status, msg): return {'status':status, 'data':data, 'message':msg} # return: # {status:true/false - if cleaning succeeded # data:cleaned_data - empty dict if status = false # message:error_message - empty if status = true try: data['id'] = int(data['id']) except (ValueError, TypeError): # this shouldn't happen return r(False, _("Wrong product id")) if data['id'] != -1: # check if product belongs to this company and if he has the required permissions try: p = Product.objects.get(id=data['id'], company=company) except Product.DoesNotExist: return r(False, _("Cannot edit product: it does not exist")) if p.company != company or not has_permission(user, company, 'product', 'edit'): return r(False, _("You have no permission to edit this product")) # name if not data['name']: return r(False, _("No name entered")) elif len(data['name']) > max_field_length(Product, 'name'): return r(False, _("Name too long")) else: if data['id'] == -1: # when adding new products: # check if a product with that name exists p = Product.objects.filter(company=company,name=data['name']) if p.count() > 0: return r(False, _("There is already a product with that name") + \ " (" + _("code") + ": " + p[0].code + ")") data['name'] = data['name'].strip() # category: must be present and must exist if not data.get('category_id'): return r(False, _("No category assigned")) else: try: data['category_id'] = int(data['category_id']) data['category'] = Category.objects.get(id=data['category_id'], company=company) except Category.DoesNotExist: return r(False, _("Selected category does not exist")) # price if len(data['price']) > g.DECIMAL['currency_digits']+1: return r(False, _("Price too long")) ret = parse_decimal(user, company, data['price'], g.DECIMAL['currency_digits']) if not ret['success']: return r(False, _("Check price notation")) data['price'] = ret['number'] # purchase price if 'purchase_price' in data: if len(data['purchase_price']) > g.DECIMAL['currency_digits']+1: return r(False, _("Purchase price too long")) if len(data['purchase_price']) > 1: # purchase price is not mandatory, so don't whine if it's not entered ret = parse_decimal(user, company, data['purchase_price'], g.DECIMAL['currency_digits']) if not ret['success']: return r(False, _("Check purchase price notation")) data['purchase_price'] = ret['number'] # unit type (probably doesn't need checking if not data['unit_type'] in dict(g.UNITS): return r(False, _("Invalid unit type")) # image: if data['change_image'] == True: if 'image' in data and data['image']: # a new image has been uploaded data['image'] = import_color_image(data['image'], g.IMAGE_DIMENSIONS['product'], 'fill') if not data['image']: # something has gone wrong during conversion return r(False, _("Image upload failed")) else: # image will be deleted in view pass else: # no change regarding images data['image'] = None # code: must exist and must be unique data['code'] = data['code'].strip() if not data['code']: return r(False, _("No code entered")) else: if len(data['code']) > max_field_length(Product, 'code'): return r(False, _("Code too long")) try: p = Product.objects.get(company=company, code=data['code']) if p.id != data['id']: # same ids = product is being edited, so codes can be the same # if ids are not the same, it's either new product or another product's code return r(False, _("A product with this code already exists: ") + p.name) except Product.DoesNotExist: pass # there is no product with this code, everything is ok # shortcut: if exists, must be unique data['shortcut'] = data['shortcut'].strip() if data['shortcut']: if len(data['shortcut']) > max_field_length(Product, 'shortcut'): return r(False, _("Shortcut too long")) try: p = Product.objects.get(company=company, shortcut=data['shortcut']) if p.id != data['id']: return r(False, _("A product with this shortcut already exists: ") + p.name) except Product.DoesNotExist: pass # ok # description, notes - anything can be entered data['description'] = data['description'].strip() data['private_notes'] = data['private_notes'].strip() # tax: id should be among tax rates for this company try: tax = Tax.objects.get(id=int(data['tax_id'])) except: return r(False, _("Invalid tax rate")) del data['tax_id'] data['tax'] = tax # stock if len(data['stock']) > g.DECIMAL['quantity_digits']: return r(False, _("Stock number too big")) ret = parse_decimal(user, company, data['stock'], g.DECIMAL['quantity_digits']-g.DECIMAL['quantity_decimal_places']-1) if not ret['success']: return r(False, _("Check stock notation")) else: data['stock'] = ret['number'] # it cannot be negative if data['stock'] < decimal.Decimal('0'): return r(False, _("Stock cannot be negative")) return {'status': True, 'data': data}