def _edit_impl(self): discount_id = self.request.matchdict.get('discount_id') discount = None if discount_id: discount = Discount.load(discount_id) self.forbid_if(not discount or discount.enterprise_id != self.enterprise_id) else: discount = Discount() included_products = discount.get_products() not_included_products = [] for prod in Product.find_all(self.enterprise_id): found = False for incl in included_products: if incl.product_id == prod.product_id: found = True break if found == False: not_included_products.append(prod) return { 'discount': discount, 'included_products' : included_products, 'not_included_products' : not_included_products, 'excluded' : Product.find_all(self.enterprise_id), 'tomorrow' : util.today_date() + datetime.timedelta(days=1), 'plus14' : util.today_date() + datetime.timedelta(days=14) }
def test_save_existing(self): ent = Enterprise.find_by_name('Healthy U Store') category_id = self._create_new() R = self.get('/crm/product/category/list') assert R.status_int == 200 R.mustcontain('Test Category') R.mustcontain('Product Search') R = self.get('/crm/product/category/edit/%s' % category_id) R.mustcontain('Edit Product Category') f = R.forms['frm_category'] self.assertEqual(f['category_id'].value, category_id) self.assertEqual(f['name'].value, 'Test Category') self.assertEqual(f['seo_keywords'].value, 'SEO Test') self.assertEqual(f['description'].value, 'Test Description') f.set('name', 'Test Category New') f.set('seo_keywords', 'SEO Test New') for prd in Product.find_all(ent.enterprise_id)[:3]: f.set('child_incl_%s' % prd.product_id, prd.product_id) R = f.submit('submit') self.assertEqual(R.status_int, 302) R = R.follow() assert R.status_int == 200 f = R.forms['frm_category'] R.mustcontain('Edit Product Category') self.assertEqual(f['category_id'].value, category_id) self.assertEqual(f['name'].value, 'Test Category New') self.assertEqual(f['seo_keywords'].value, 'SEO Test New') for prd in Product.find_all(ent.enterprise_id)[:3]: self.assertEqual(f['child_incl_%s' % prd.product_id].checked, True) self._delete_new(category_id)
def import_product_list(company_id, filename='/tmp/products/products.csv'): company = Company.load(company_id) default_campaign = company.default_campaign products = [] with open(filename) as f: products = f.readlines() products = [p.rstrip() for p in products[1:]] product_categories = {} for pline in products: log(pline) (product_name, category_id, pic) = pline.split(',') pic = pic.strip() key = '%s%s' % (product_name.strip(), category_id.strip()) cat = ProductCategory.load(category_id.strip(), False) prod = None if key in product_categories: prod = Product.load(product_categories[key][0], False) else: prod = Product() prod.company = company prod.name = product_name.strip() prod.type = 'Parent or Child' prod.save() prod.flush() product_categories[key] = [str(prod.product_id), str(cat.category_id)] ass = Asset() ass.fk_type = 'Product' ass.fk_id = prod.product_id ass.enterprise_id = company.enterprise_id ass.name = os.path.basename(pic) ass.extension = os.path.splitext(pic)[1] ass.save() ass.flush() storage_root = Asset.get_storage_root() if not storage_root: storage_root = '/apps/pvs/storage' fs_real_dir = "{root}/{reldir}".format(root=storage_root, reldir=ass.relative_dir) util.mkdir_p(fs_real_dir) fs_real_path = "{fs_real_dir}/{assid}{ext}".format(fs_real_dir=fs_real_dir, assid=ass.id, ext=ass.extension) shutil.copyfile(pic, fs_real_path) for pc in product_categories: pcat = product_categories[pc] cat = ProductCategory.load(pcat[1], False) cat.add_product(pcat[0]) db.commit()
def save_inventory(self): prod = Product.load(self.request.POST.get('id')) self.forbid_if(not prod or prod.company.enterprise_id != self.enterprise_id) InventoryJournal.create_new(prod, 'Inventory Adjust', float(self.request.POST.get('inventory', 0))) prod.name = self.request.POST.get('name') prod.manufacturer = self.request.POST.get('manufacturer') prod.unit_cost = util.nvl(self.request.POST.get('unit_cost'), 0.0) prod.sku = self.request.POST.get('sku') prod.inventory_par = util.nvl(self.request.POST.get('inventory_par'), None) prod.save() # save all the prices, prefixed by "cmp_" for k in self.request.POST.keys(): if k.startswith('cmp_'): match = re.search(r'^.*_(.*)', k) if match: campaign = Campaign.load(match.group(1)) price = self.request.POST.get(k) if price: price = util.float_(price) prod.set_price_only(campaign, price) else: prod.remove_price(campaign) prod.invalidate_caches(campaign_id=campaign.campaign_id) return 'True'
def product(self): product_id = self.request.matchdict.get("product_id") if not util.is_uuid(product_id): # it's not really a product ID, but a search string from a bot. raise HTTPFound("/ecom/search?search=%s" % product_id) prod = Product.load(product_id) self.redir_if(not prod or not prod.enabled or not prod.web_visible) page = self.request.matchdict.get( "page", util.nvl(prod.render_template, "product") ) # /product/{product_id}/{page} self.session["last_product_id"] = product_id self.session["back_link"] = "/product/%s" % product_id params = self.params() self._add_to_recent_products(prod) params["product"] = prod params["products_also_liked"] = SmartCatalog.also_liked_product_list(prod, params["campaign"]) params["products_related"] = SmartCatalog.related_product_list(prod, params["campaign"]) params["product_attributes"] = self._prep_product_attributes(prod.get_product_attributes()) params["attrs"] = prod.get_attrs() params["price"] = SmartPricing.product_price(prod, params["campaign"]) (params["seo_title"], params["seo_keywords"], params["seo_description"]) = SmartSeo.product_seo( prod, self.request.ctx.site ) return self.render(page, params)
def show_returns(self): product_id = self.request.matchdict['product_id'] product = Product.load(product_id) self.forbid_if(not product or product.company.enterprise_id != self.enterprise_id) return {'product' : product, 'events' : util.select_list(StatusEvent.find_all_applicable(self.enterprise_id, product), 'event_id', 'display_name'), 'returns' : ProductReturn.find(product)}
def _show_prep(self, report_id): report = Report.load(report_id) campaigns = products = companies = users = vendors = None if report.show_campaign_id: campaigns = util.select_list(Campaign.find_all(self.enterprise_id), 'campaign_id', 'name', True) if report.show_vendor_id: vendors = util.select_list(Vendor.find_all(self.enterprise_id), 'vendor_id', 'name', True) if report.show_company_id: companies = util.select_list(Company.find_all(self.enterprise_id), 'company_id', 'name', True) if report.show_user_id: users = util.select_list(Users.find_all(self.enterprise_id), 'user_id', 'user_id', True) if report.show_product_id: products = util.select_list(Product.find_all(self.enterprise_id), 'product_id', 'name', True) return { 'today' : util.today_date(), 'tomorrow' : util.tomorrow(), 'thirty_ago' : util.today_date() - datetime.timedelta(days=30), 'rpt_end_dt' : self.request.GET.get('rpt_end_dt'), 'rpt_start_dt' : self.request.GET.get('rpt_start_dt'), 'enterprise_id' : self.enterprise_id, 'report' : report, 'campaigns' : campaigns, 'products' : products, 'companies' : companies, 'users' : users, 'vendors' : vendors }
def inventory_list(self): products = Product.find_by_vendor(self.request.ctx.user.vendor) if self.request.ctx.user and self.request.ctx.user.is_vendor_user() else Product.find_all(self.enterprise_id) #pylint: disable-msg=E1120 campaigns = Campaign.find_all(self.enterprise_id) response = { 'page': 1, 'total': 1, 'records': len(products)} rows = [] for prod in products: #log.debug('%s %s/%s' % (p.product_id, i+1, len(products))) # blank spot at the beginning of the row is to make room for the # action buttons. don't remove it. cells = ['', unicode(prod.product_id), util.nvl(prod.name), util.nvl(prod.sku), util.nvl(prod.manufacturer), util.nvl(unicode(prod.inventory)), util.nvl(unicode(prod.inventory_par)), util.nvl(unicode(prod.unit_cost))] # the column ordering in the UI is dependant on the order of the # campaigns that comes back from Campaign.find_all(). We use the # same ordering here so we are fine not adding some campaign ID here. for camp in campaigns: cells.append(util.nvl(util.money(prod.get_retail_price(camp)))) rows.append({'id': str(prod.product_id), 'cell': cells}) response['rows'] = rows return json.dumps(response)
def _prep_add_order_dialog(self, customer_id): customer = Customer.load(customer_id) self.forbid_if(not customer or customer.campaign.company.enterprise_id != self.enterprise_id) products = Product.find_by_campaign(customer.campaign) return { 'customer' : customer, 'products' : products }
def upload_picture(self): product_id = self.request.matchdict.get('product_id') product = Product.load(product_id) self.forbid_if(not product or product.company.enterprise_id != self.enterprise_id) ass = Asset.create_new(product, self.enterprise_id, self.request) self.flash('Uploaded new image to product') product.invalidate_caches() return str(ass.id)
def delete(self): product_id = self.request.matchdict.get('product_id') product = Product.load(product_id) self.forbid_if(not product or str(product.company.enterprise_id) != str(self.enterprise_id)) product.mod_dt = util.now() product.delete_dt = util.now() Status.add(None, product, StatusEvent.find(self.enterprise_id, 'Product', 'DELETED'), 'Product Deleted') product.invalidate_caches() return 'True'
def delete_picture(self): product_id = self.request.matchdict.get('product_id') product = Product.load(product_id) self.forbid_if(not product or product.company.enterprise_id != self.enterprise_id) asset_id = self.request.matchdict.get('asset_id') asset = Asset.load(asset_id) self.forbid_if(asset.fk_type != 'Product' or str(asset.fk_id) != str(product.product_id)) asset.delete() return 'True'
def autocomplete_by_name(self): if 'search_key' in self.request.GET and self.request.GET.get('search_key'): srch = self.request.GET.get('search_key') # customer_id = self.request.GET.get('customer_id') # if customer_id: # customer = Customer.load(customer_id) # lnames = Product.find_names_by_name_and_campaign(self.enterprise_id, srch, self.request.GET.get('max_rows', 10), customer.campaign) lnames = Product.find_names_by_name(self.enterprise_id, srch, self.request.GET.get('max_rows', 10)) return json.dumps(lnames)
def show_purchases(self): product_id = self.request.matchdict['product_id'] from pvscore.model.crm.purchase import PurchaseOrderItem product = Product.load(product_id) self.forbid_if(not product or product.company.enterprise_id != self.enterprise_id) return {'product' : product, 'events' : util.select_list(StatusEvent.find_all_applicable(self.enterprise_id, product), 'event_id', 'display_name'), 'purchase_order_items' : PurchaseOrderItem.find_by_product(product) }
def save_status(self): product_id = self.request.POST['product_id'] product = Product.load(product_id) self.forbid_if(not product or product.company.enterprise_id != self.enterprise_id) event = StatusEvent.load(self.request.POST['event_id']) self.forbid_if(not event or (not event.is_system and event.enterprise_id != self.enterprise_id)) note = self.request.POST.get('note') Status.add(None, product, event, note, self.request.ctx.user) return HTTPFound('/crm/product/show_history/%s' % product_id)
def _edit_impl(self): purchase_order_id = self.request.matchdict.get('purchase_order_id') purchase = PurchaseOrder.load(purchase_order_id) if purchase_order_id else PurchaseOrder() return { 'companies' : util.select_list(Company.find_all(self.enterprise_id), 'company_id', 'name'), 'vendors' : util.select_list(Vendor.find_all(self.enterprise_id), 'vendor_id', 'name', True), 'products' : Product.find_all(self.enterprise_id), 'purchase' : purchase, 'events' : util.select_list(StatusEvent.find_all_applicable(self.enterprise_id, purchase), 'event_id', 'display_name') if purchase.purchase_order_id else [] }
def search(self): page = self.request.matchdict.get("page", "search_results") params = self.params() params["subset"] = "search" params["products"] = util.page_list( Product.catalog_search(self.enterprise_id, str(util.nvl(self.request.GET.get("search"))).strip()), self.request.GET.get("offset"), self.request.GET.get("limit"), ) return self.render(page, params)
def remove(self): if not 'cart' in self.session: return 'False' #pragma: no cover redir = self.request.GET.get('redir') cart = self.session['cart'] product_id = self.request.matchdict.get('product_id') product = Product.load(product_id) cart.remove_item(product) self.session.changed() return 'True' if not redir else HTTPFound(redir)
def update(self): product_id = self.request.matchdict.get('product_id') quantity = self.request.matchdict.get('quantity') redir = self.request.GET.get('redir') cart = self.session['cart'] product = Product.load(product_id) cart.remove_item(product) cart.add_item(product, self.request.ctx.campaign, quantity) self.session.changed() return 'True' if not redir else HTTPFound(redir)
def add(self): """ KB: [2013-02-20]: MOD ATTR: CartController.add : Allow for ajax of adding a simple item (HUS), or post/redir for adding products with attributes. """ product_id = self.request.matchdict.get('product_id') quantity = self.request.matchdict.get('quantity') redir = self.request.POST.get('redir') note = self.request.POST.get('note') cart = self.session['cart'] product = Product.load(product_id) cart.add_item(product, self.request.ctx.campaign, quantity, note=note) self.session.changed() return 'True' if not redir else HTTPFound(redir)
def _edit_impl(self): category_id = self.request.matchdict.get('category_id') companies = util.select_list(Company.find_all(self.enterprise_id), 'company_id', 'name') if category_id: category = ProductCategory.load(category_id) self.forbid_if(not category or category.company.enterprise_id != self.enterprise_id) else: category = ProductCategory() all_products = Product.find_all(self.enterprise_id) return {'companies' : companies, 'category' : category, 'all_products' : all_products}
def add_order(self): """ KB: [2013-02-20]: MOD ATTR CustomerController.add_order : Modify to allow for attributes to be passed in the post. """ customer_id = self.request.matchdict.get('customer_id') cust = Customer.load(customer_id) self.forbid_if(not cust) # KB: [2013-02-24]: products are passed as products[$product_id] = quantity product_ids = {} for key in self.request.POST.keys(): if key.startswith('products'): match = re.search(r'^.*\[(.*)\]', key) if match: pid = match.group(1) quant = float(util.nvl(self.request.POST.get(key), '1.0')) if pid not in product_ids: product_ids[pid] = 0 product_ids[pid] += quant # KB: [2013-02-24]: attributes are passed as attributes[$attribute_id] = $parent_product_id attributes = {} for key in self.request.POST.keys(): if key.startswith('attributes'): match = re.search(r'^.*\[(.*)\]', key) if match: attribute_product_id = match.group(1) parent_product_id = self.request.POST.get(key) attributes[attribute_product_id] = { 'parent_product' : Product.load(parent_product_id), 'attribute_product' : Product.load(attribute_product_id) } order_id = self._add_order_impl(customer_id, product_ids, attributes, None, self.request.ctx.user, self.request.POST.get('discount_id'), self.request.POST.get('campaign_id', self.request.GET.get('campaign_id')), self.incl_tax) cust.invalidate_caches() return str(order_id)
def add_attributed_product(self): """ KB: [2013-02-24]: var attributes = {}; attributes[$('#color_id').val()] = 0; // quantity of zero, unless its really something that requires a quantity. attributes[$('#size_id').val()] = 0; $.post('/ecom/cart/add_attributed_product', { product_id : base_product_id, attributes : attributes, quantity : $('#qty').val() }, function(resp) { if (resp == 'True') { window.location = '/product/' + base_product_id; } }); """ redir = self.request.POST.get('redir') product_id = self.request.POST.get('product_id') quantity = self.request.POST.get('quantity') cart = self.session['cart'] attributes = {} for key in self.request.POST.keys(): if key.startswith('attributes'): match = re.search(r'^.*\[(.*)\]', key) if match: pid = match.group(1) quant = float(util.nvl(self.request.POST.get(key), '1.0')) attributes[pid] = { 'quantity' : quant, 'product' : Product.load(pid) } product = Product.load(product_id) self.forbid_if(not product) cart.add_item(product, self.request.ctx.campaign, quantity, attributes=attributes) self.session.changed() return 'True' if not redir else HTTPFound(redir)
def _test_save_status(self): ent = Enterprise.find_by_name('Healthy U Store') product_id = self._create_new() product = Product.load(product_id) events = StatusEvent.find_all_applicable(ent.enterprise_id, product) R = self.post('/crm/product/save_status', {'product_id': product_id, 'note' : 'Test Note %s' % product_id, 'event_id' : events[0].event_id}) assert R.status_int == 200 R.mustcontain('Product Event History') R.mustcontain('Test Note %s' % product_id) # assert that the edit page has the name of the event in green # at the top. R = self.get('/crm/product/edit/%s' % product_id) assert R.status_int == 200 R.mustcontain('Edit Product') R.mustcontain(events[0].short_name) self._delete_new(product_id)
def _site_purchase(self, cust, cart=None): #pylint: disable-msg=R0912,R0915 """ KB: [2013-02-20]: MOD ATTR CustomerController._site_purchase : Allow for attributes passed in the post """ bill = self._create_billing(cust) campaign = Campaign.load(cust.campaign_id) if not cart: cart = Cart() product_skus = self.request.POST.getall('product_sku') for sku in product_skus: prod = Product.find_by_sku(self.enterprise_id, campaign, sku) if prod: cart.add_item(product=prod, campaign=cust.campaign, start_dt=self.request.POST.get('bill_start_dt') ) else: self.flash("No such product sku: %s" % sku) self.raise_redirect(self.request.referrer) order = cust.add_order(cart, None, self.enterprise_id, campaign, order_note=self.request.POST.get('order_note')) return self._bill_credit_card(cust, order, bill)
def _test_save_inventory(self): ent = Enterprise.find_by_name('Healthy U Store') cmpns = Campaign.find_all(ent.enterprise_id) R = self.get('/crm/product/inventory_list') assert R.status_int == 200 prods = json.loads(R.body) self.assertGreater(prods['records'], 100) self.assertEqual(prods['records'], len(prods['rows'])) # get the first product ID prod = prods['rows'][1]['cell'] # ['', '1451', '5-HTP 100 mg- Pharmax', 'SUP-1003', 'Seroyal', '123', '8.0', '15.0', '25.00', '', '25.00', '25.00'] pid = prod[1] name = prod[2] #sku = prod[3] #manu = prod[4] inventory = int(prod[5]) inventory_par = prod[6] unitcost = prod[7] R = self.post('/crm/product/save_inventory', {'id' : pid, 'inventory' : inventory + 10, 'inventory_par' : inventory_par, 'name' : name + ' xxx', 'unit_cost' : unitcost, 'cmp_%s' % cmpns[0].campaign_id : '999', 'cmp_%s' % cmpns[1].campaign_id : ''}) self.assertEquals(R.body, 'True') prod = Product.load(pid) tot = InventoryJournal.total(prod) self.assertEqual(tot, inventory + 10) self.assertEqual(999, prod.campaign_prices[cmpns[0].campaign_id].retail_price) self.assertEqual(True, cmpns[1].campaign_id not in prod.campaign_prices.keys()) R = self.get('/crm/product/edit/%s' % pid) assert R.status_int == 200 f = R.forms['frm_product'] R.mustcontain('Edit Product') self.assertEqual(f['product_id'].value, pid) self.assertEqual(f['name'].value, name + ' xxx')
def test_complete_po(self): purchase_order_id = self._create_new() ent = Enterprise.find_by_name('Healthy U Store') prods = Product.find_all(ent.enterprise_id) product_id = prods[0].product_id # add a new one R = self.post('/crm/purchase/save_purchase_order_item/%s?product_id=%s' % (str(purchase_order_id), product_id), {'order_note' : 'Note Note', 'quantity' : 10, 'unit_cost' : 123}) json.loads(R.body) assert R.status_int == 200 R = self.get('/crm/purchase/complete/%s' % purchase_order_id) assert R.status_int == 200 R.mustcontain('True') R = self.get('/crm/purchase/edit/%s' % purchase_order_id) assert R.status_int == 200 R.mustcontain('Completed:') self._delete_new(purchase_order_id)
def test_order_item_add_delete(self): ent = Enterprise.find_by_name('Healthy U Store') purchase_order_id = self._create_new() prods = Product.find_all(ent.enterprise_id) product_id = prods[0].product_id # add a new one R = self.post('/crm/purchase/save_purchase_order_item/%s?product_id=%s' % (str(purchase_order_id), product_id), {'order_note' : 'Note Note', 'quantity' : 10, 'unit_cost' : 123}) oitem = json.loads(R.body) assert R.status_int == 200 order_item_id = oitem['id'] # get the json from it R = self.get('/crm/purchase/order_item_json/%s/%s' % (purchase_order_id, order_item_id)) assert R.status_int == 200 oitem = json.loads(R.body) self.assertEqual(oitem['order_item_id'], order_item_id) self.assertEqual(oitem['note'], 'Note Note') self.assertEqual(int(oitem['unit_cost']), 123) self.assertEqual(int(oitem['quantity']), 10) # complete the item R = self.get('/crm/purchase/complete_item/%s/%s' % (purchase_order_id, order_item_id)) assert R.status_int == 200 R.mustcontain('True') #R = self.get('/crm/purchase/show_history/%s' % purchase_order_id) #assert R.status_int == 200 #R.mustcontain('PurchaseOrder Completed') # delete the oi R = self.get('/crm/purchase/delete_purchase_order_item/%s/%s' % (purchase_order_id, order_item_id)) assert R.status_int == 200 R.mustcontain('True') self._delete_new(purchase_order_id)
def _add_order_impl(self, customer_id, product_ids, attributes, prices, user, discount_id, campaign_id, incl_tax=True): #pylint: disable-msg=R0913 """ KB: [2013-02-20]: attributes = [{quantity : 0, product : <Product...>}, {...}] """ cust = Customer.load(customer_id) self.forbid_if(not cust or cust.campaign.company.enterprise_id != self.enterprise_id) cart = Cart() campaign_id = campaign_id if campaign_id else cust.campaign_id cart.discount_id = discount_id for pid in product_ids.keys(): quantity = product_ids[pid] price = prices[pid] if prices and pid in prices else None attrs = {} for attr in [attr['attribute_product'] for attr in attributes.values() if str(attr['parent_product'].product_id) == pid]: attrs[attr.product_id] = { 'quantity' : 0, 'product' : attr} cart.add_item(product=Product.load(pid), campaign=cust.campaign, quantity=quantity, attributes=attrs, base_price=price) order = cust.add_order(cart, user, self.enterprise_id, cust.campaign, incl_tax=incl_tax) order.flush() return order.order_id
def _edit_impl(self): product_id = self.request.matchdict.get('product_id') campaigns = Campaign.find_all(self.enterprise_id) companies = util.select_list(Company.find_all(self.enterprise_id), 'company_id', 'name') product_types = Product.get_types() vendors = util.select_list(Vendor.find_all(self.enterprise_id), 'vendor_id', 'name', True) categories = util.select_list(ProductCategory.find_all(self.enterprise_id), 'category_id', 'name', True) if product_id: product = Product.load(product_id) self.forbid_if(not product or product.company.enterprise_id != self.enterprise_id) product_categories = ProductCategory.find_by_product(product) else: product = Product() product_categories = [] self.forbid_if(self.request.ctx.user.is_vendor_user() and product.product_id and not self.request.ctx.user.vendor_id == product.vendor_id) children = product.get_children() other_products = product.find_eligible_children() non_children = [] for prod in other_products: found = False for kid in children: if kid.child_id == prod.product_id: found = True break if found == False: non_children.append(prod) return { 'product' : product, 'campaigns' : campaigns, 'companies' : companies, 'product_types' : product_types, 'vendors' : vendors, 'categories' : categories, 'product_categories' : product_categories, 'children' : children, 'non_children': non_children, 'other_products' : other_products, 'events' : util.select_list(StatusEvent.find_all_applicable(self.enterprise_id, product), 'event_id', 'display_name'), 'is_attribute' : self.request.GET.get('is_attribute') == 'True', 'parent_product' : Product.load(self.request.GET.get('parent_id')) if 'parent_id' in self.request.GET else None }