Esempio n. 1
0
 def test_add_item_to_inventory_that_we_dont_have_records_transaction(self):
     random_item = random.sample(list(Book.select()), 1)[0]
     fakeargs = dict(
         title=random_item.title.booktitle,
         authors=random_item.title.authors_as_string(),
         publisher=random_item.title.publisher,
         distributor=random_item.distributor,
         owner="woodenshoe",
         listprice=random_item.listprice,
         ourprice=random_item.ourprice,
         isbn=random_item.title.isbn,
         categories=random_item.title.categories_as_string(),
         location=random_item.location,
         quantity=1,
         known_title=True,
         types=random_item.title.type,
         kind=random_item.title.kind.id,
         kind_name=random_item.title.kind.kindName,
     )
     response = self._my_app.post("/admin/add_item_to_inventory", fakeargs)
     nowish = Now.now.strftime("%Y-%m-%d %H:%M:%S")
     confirm = Transaction.select("date > %s" % nowish).filter(
         "info RLIKE %s" % random_item.title.booktitle)
     self.assertTrue(
         confirm,
         "test_add_item_to_inventory does not add item to inventory")
Esempio n. 2
0
 def retrieve(self,number):
     isbn=number
     if len(number)==13:
         isbn=upc2isbn(number)
     books =  Book.select(AND(Book.q.titleID==Title.q.id,Title.q.isbn==isbn,Book.q.status=="STOCK") )
     print books
     if len(list(books))==1:
         theBook = books[0]
         if theBook:
             print theBook
             self.setBook(theBook)
             desc=theBook.title.booktitle
             self.setDescription("%s" % desc)
             self.source=theBook.title.kind.kindName
             self.setPrice(theBook.listprice)
             self.setDistributor(theBook.distributor)
             return 1
     else:
         if len(list(books))>1:
             from popups.browseinventory import BrowseInventoryPopup
             self.browser=BrowseInventoryPopup(self.parent,{"isbn":isbn,"status":"STOCK"})
             self.browser.CenterOnScreen()
             self.browser.ShowModal()
             return -1
         else:
             return 0
Esempio n. 3
0
 def test_add_item_to_inventory_that_we_dont_have_records_transaction(self):
     random_item=random.sample(list(Book.select()), 1)[0]
     fakeargs=dict(title=random_item.title.booktitle, authors=random_item.title.authors_as_string(), publisher=random_item.title.publisher, distributor=random_item.distributor, owner='woodenshoe', listprice=random_item.listprice, ourprice=random_item.ourprice, isbn=random_item.title.isbn, categories=random_item.title.categories_as_string(), location=random_item.location, quantity=1, known_title=True, types=random_item.title.type, kind_name=random_item.title.kind.kindName)
     response=self._my_app.post('/admin/add_item_to_inventory', fakeargs)
     nowish=mx.DateTime.now().strftime('%Y-%m-%d %H:%M:%S')
     confirm=Transaction.select('date > %s' % nowish).filter('info RLIKE %s' % random_item.title.booktitle)
     self.assertTrue(confirm, "test_add_item_to_inventory does not add item to inventory")
Esempio n. 4
0
 def test_bookedit_functional(self):
     random_item = random.sample(list(Book.select()), 1)[0]
     response = self._my_app.get("/bookedit", {"id": random_item.id})
     code, error = tidylib.tidy_document(response.body,
                                         options={
                                             "show-errors": 1,
                                             "show-warnings": 0
                                         })
     self.assertFalse(error, "/bookedit did not return valid html page")
Esempio n. 5
0
 def PayConsigner(self,event):
     
     owner=self.consigner.GetStringSelection()
     #print self.consigner.GetCurrentSelection()
     #print self.consigner.GetSelection()
     #print self.consigner.GetStringSelection()
     books=Book.select(Book.q.owner==owner)
     frame = wxFrame(None, -1, "check in list" , pos=(50,50), size=(500,600),
                      style=wxNO_FULL_REPAINT_ON_RESIZE|wxDEFAULT_FRAME_STYLE)
     frame.Show(True)
     win = ConsignmentListPopup(frame,books,owner)
     self.Close()
Esempio n. 6
0
    def Checkin(self,event):
        
        status=self.borrower.GetStringSelection()
        books=Book.select(Book.q.status==status)
        frame = wxFrame(None, -1, "check in list" , pos=(50,50), size=(500,600),
                         style=wxNO_FULL_REPAINT_ON_RESIZE|wxDEFAULT_FRAME_STYLE)
        win = CheckinListPopup(frame,books,status)
        #win.Show()

        self.Destroy()
        win.Raise()   
        
        frame.Raise()
        frame.Show()    
        frame.SetFocus()
 def _set_status_SOLD(self):
     random_item = random.sample(list(Book.select(Book.q.status != "SOLD")),
                                 1)[0]
     random_item_fields = list([
         string(x) for x in [
             radom_item.status,
             random_item.sold_when,
             random_item.inventoried_when,
         ]
     ])
     random_item.status = "SOLD"
     try:
         assertTrue(random_item.status == "STOCK")
         assertTrue(random_item.inventoried_when == datetime.now().date())
     finally:
         random_item.status = random_item_fields[0]
         random_item.sold_when = random_item_fields[1]
Esempio n. 8
0
    def PayConsigner(self, event):

        owner = self.consigner.GetStringSelection()
        print self.consigner.GetCurrentSelection()
        print self.consigner.GetSelection()
        print self.consigner.GetStringSelection()
        books = Book.select(Book.q.owner == owner)
        frame = wxFrame(None,
                        -1,
                        "check in list",
                        pos=(50, 50),
                        size=(500, 600),
                        style=wxNO_FULL_REPAINT_ON_RESIZE
                        | wxDEFAULT_FRAME_STYLE)
        frame.Show(True)
        win = ConsignmentListPopup(frame, books, owner)
        self.Close()
Esempio n. 9
0
    def Checkin(self, event):

        status = self.borrower.GetStringSelection()
        books = Book.select(Book.q.status == status)
        frame = wxFrame(None,
                        -1,
                        "check in list",
                        pos=(50, 50),
                        size=(500, 600),
                        style=wxNO_FULL_REPAINT_ON_RESIZE
                        | wxDEFAULT_FRAME_STYLE)
        win = CheckinListPopup(frame, books, status)
        #win.Show()

        self.Destroy()
        win.Raise()

        frame.Raise()
        frame.Show()
        frame.SetFocus()
Esempio n. 10
0
    def getInventory(self,queryTerms):
        #print queryTerms
        keys=queryTerms.keys()
        
        isbnSelect=""
        kindSelect=""
        statusSelect=""
        titleSelect=""
        authorSelect=""
        categorySelect=""
        clauseTables=[]

        if "kind" in keys: # joins suck, avoid if possible
            kind_map={}
            for k in [(x.kindName,x.id) for x in list(Kind.select())]:
                kind_map[k[0]]=k[1]
            try:
                kind_id=kind_map[queryTerms['kind']]
                kindSelect=Book.sqlrepr(AND(Field("book","title_id")==Field("title","id"), Field("title","kind_id")==kind_id))
            except: 
                pass
            
        if 'status' in keys:
            statusSelect=Book.sqlrepr(Field("book","status")==queryTerms["status"])
            

        if ('title' in keys) or ('authorName' in keys) or ('kind' in keys) or ('categoryName' in keys) or ('isbn' in keys):
            clauseTables.append('title') 
            #we are going to need to do a join 

            if 'title' in keys:
                titleSelect=Book.sqlrepr(AND(Field("book","title_id")==Field("title","id"), RLIKE(Field("title","booktitle"), queryTerms["title"])))


            if 'isbn' in keys:
                titleSelect=Book.sqlrepr(AND(Field("book","title_id")==Field("title","id"), Field("title","isbn")==queryTerms["isbn"]))


            if 'authorName' in keys:
                #authorSelect="""book.title_id = title.id AND author.title_id=title.id AND author.author_name RLIKE %s""" % (Book.sqlrepr(queryTerms["authorName"]))    
               authorSelect=Book.sqlrepr(AND(Field("book","title_id")==Field("title","id"), Field("author","id")==Field("author_title","author_id"), Field("title","id")==Field("author_title","title_id"), RLIKE(Field("author","author_name"), queryTerms["authorName"])))
               clauseTables.append('author')
               clauseTables.append('author_title')
            
            if 'categoryName' in keys:
                categorySelect="""book.title_id = title.id AND category.title_id=title.id AND category.category_name RLIKE %s""" % (Book.sqlrepr(queryTerms["categoryName"]))
                #categorySelect=Book.sqlrepr(AND(Field("book","title_id")==Field("title","id"), Field("category","title_id")==Field("title","id"), RLIKE(Field("category","category_name"), queryTerms["categoryName"])))
                clauseTables.append('category')
            # At this time, ubuntu install sqlobject 0.6.1 if apt-get install python2.4-sqlobject,
            # which make the search crash, since the distinct attribute is defined somewhere after 0.6.1 
        try:
            books=Book.select(
                string.join([term for term in [statusSelect,titleSelect,authorSelect,kindSelect,categorySelect] if term !=""]," AND "),
                clauseTables=clauseTables,
                distinct=True    )
        except TypeError:
            books=Book.select(
                string.join([term for term in [statusSelect,titleSelect,authorSelect,kindSelect,categorySelect] if term !=""]," AND "),
                clauseTables=clauseTables   )
            
        
        results={}
        i=1
        for b in books:
            theTitle=b.title.booktitle
            authorString=string.join([a.authorName for a in b.title.author],",")
            categoryString=string.join([c.categoryName for c in b.title.categorys],",")
            results[i]=(string.capitalize(theTitle),
                        authorString, 
                        b.listprice  if b.listprice is not None else '',
                        b.title.publisher if b.title.publisher is not None else '',
                        b.status if b.status is not None else'',
                        b.title.isbn,
                        b.distributor if b.distributor is not None else '',
                        b.location.locationName if b.location is not None else '',
                        b.notes if b.notes is not None else '',
                        b.id,
                        b.title.kind and b.title.kind.kindName if b.title.kind is not None else '',
            categoryString,
            b.title.type if b.title.type is not None else '')
        #~ for b in books:
            #~ theTitle=b.title.booktitle.format()
            #~ authorString=string.join([a.authorName.format() for a in b.title.author],",")
            #~ categoryString=string.join([c.categoryName.format() for c in b.title.categorys],",")
            #~ results[i]=(string.capitalize(theTitle),
                        #~ authorString, 
                        #~ b.listprice  if b.listprice is not None else '',
                        #~ b.title.publisher.format() if b.title.publisher is not None else '',
                        #~ b.status.format() if b.status is not None else'',
                        #~ b.title.isbn,
                        #~ b.distributor.format() if b.distributor is not None else '',
            #~ b.location.locationName.format() if b.location is not None else '',
                        #~ b.notes.format() if b.notes is not None else '',
                        #~ b.id,
                        #~ b.title.kind and b.title.kind.kindName if b.title.kind is not None else '',
            #~ categoryString,
            #~ b.title.type if b.title.type is not None else '')

            i=i+1                
        #print "results are ", results
        return results
Esempio n. 11
0
    def checkout(self, **args):
        self.common()
        self._checkouttemplate.status_from = args.get("status_from", "STOCK")
        self._checkouttemplate.status_to = args.get("status_to", "RETURNED")
        self._checkouttemplate.schedules = [("list price", 1)
                                            ] + cfg.get("multiple_prices")

        if "change" in args:
            return self.addtocart(**args)
        if "finalize" in args:
            schedule_name = args["schedule"]
            schedule = [
                x for x in cfg.get("multiple_prices") + [("list price", 1)]
                if x[0] == schedule_name
            ]
            schedule_price = schedule[0][1]
            receipt = ""
            for q in cherrypy.session.get('quantities', []):

                original = q[0]
                howmany = q[1]

                for copy in list(
                        Book.select(
                            AND(Book.q.titleID == original.titleID,
                                Book.q.status == "STOCK", Book.q.listprice ==
                                original.listprice)))[0:howmany]:
                    cursor = self.conn.cursor()
                    cursor.execute(
                        """
                        INSERT INTO transactionLog SET
                        action = "SALE",
                        amount = %s,
                        cashier = %s,
                        date = NOW(),
                        info = %s,
                        schedule = %s,
                        owner = %s
                        """,
                        (copy.listprice * schedule_price, args["cashier"],
                         "[%s] %s" % (copy.distributor, copy.title.booktitle),
                         schedule_name, copy.owner))
                    copy.sellme()
                    cursor.close()
                line_pt_1 = "%s  X  %s  @ $%.2f * %i%%" % (
                    original.title.booktitle[:25], howmany, original.listprice,
                    schedule_price * 100)
                receipt = receipt + string.ljust(line_pt_1, 50) + string.rjust(
                    "$%.2f" %
                    (howmany * schedule_price * original.listprice), 10)
            return receipt

        if "restatus" in args and "status_to" in args and "status_from" in args:
            for q in cherrypy.session.get('quantities', []):
                original = q[0]
                howmany = q[1]
                for copy in list(
                        Book.select(
                            AND(Book.q.titleID == original.titleID,
                                Book.q.status == args["status_from"],
                                Book.q.listprice ==
                                original.listprice)))[0:howmany]:

                    copy.status = args["status_to"]

            cherrypy.session['quantities'] = []

        if "delete" in args:
            for q in cherrypy.session.get('quantities', []):
                original = q[0]
                original_price = original.listprice
                original_status = original.status
                original_title_id = original.titleID
                howmany = q[1]
                for copy in list(
                        Book.select(
                            AND(Book.q.titleID == original_title_id,
                                Book.q.status == original_status,
                                Book.q.listprice ==
                                original_price)))[0:howmany]:

                    Book.delete(copy.id)

            cherrypy.session['quantities'] = []

        self._checkouttemplate.quantities = cherrypy.session.get(
            'quantities', [])
        return self._checkouttemplate.respond()
Esempio n. 12
0
    def getInventory(self, queryTerms):
        keys = queryTerms.keys()

        isbnSelect = ""
        kindSelect = ""
        statusSelect = ""
        titleSelect = ""
        authorSelect = ""
        categorySelect = ""
        clauseTables = []

        if "kind" in keys:  # joins suck, avoid if possible
            kind_map = {}
            for k in [(x.kindName, x.id) for x in list(Kind.select())]:
                kind_map[k[0]] = k[1]
            try:
                kind_id = kind_map[queryTerms['kind']]
                kindSelect = Book.sqlrepr(
                    AND(
                        Field("book", "title_id") == Field("title", "id"),
                        Field("title", "kind_id") == kind_id))
            except:
                pass

        if 'status' in keys:
            statusSelect = Book.sqlrepr(
                Field("book", "status") == queryTerms["status"])

        if ('title' in keys) or ('authorName' in keys) or ('kind' in keys) or (
                'categoryName' in keys) or ('isbn' in keys):
            clauseTables.append('title')
            #we are going to need to do a join

            if 'title' in keys:
                titleSelect = Book.sqlrepr(
                    AND(
                        Field("book", "title_id") == Field("title", "id"),
                        RLIKE(Field("title", "booktitle"),
                              queryTerms["title"])))

            if 'isbn' in keys:
                titleSelect = Book.sqlrepr(
                    AND(
                        Field("book", "title_id") == Field("title", "id"),
                        Field("title", "isbn") == queryTerms["isbn"]))

            if 'authorName' in keys:
                #~ authorSelect="""book.title_id = title.id AND author.title_id=title.id AND author.author_name RLIKE %s""" % (Book.sqlrepr(queryTerms["authorName"]))
                authorSelect = Book.sqlrepr(
                    AND(
                        Field("book", "title_id") == Field("title", "id"),
                        Field("author", "id") == Field("author_title",
                                                       "author_id"),
                        Field("title", "id") == Field("author_title",
                                                      "title_id"),
                        RLIKE(Field("author", "author_name"),
                              queryTerms["authorName"])))
                clauseTables.append('author')
                clauseTables.append('author_title')

            if 'categoryName' in keys:
                #~ categorySelect="""book.title_id = title.id AND category.title_id=title.id AND category.category_name RLIKE %s""" % (Book.sqlrepr(queryTerms["categoryName"]))
                categorySelect = Book.sqlrepr(
                    AND(
                        Field("book", "title_id") == Field("title", "id"),
                        Field("category", "title_id") == Field("title", "id"),
                        RLIKE(Field("category", "category_name"),
                              queryTerms["categoryName"])))
                clauseTables.append('category')

    # At this time, ubuntu install sqlobject 0.6.1 if apt-get install python2.4-sqlobject,
# which make the search crash, since the distinct attribute is defined somewhere after 0.6.1
        try:
            books = Book.select(string.join([
                term for term in [
                    statusSelect, titleSelect, authorSelect, kindSelect,
                    categorySelect
                ] if term != ""
            ], " AND "),
                                clauseTables=clauseTables,
                                distinct=True)
        except TypeError:
            books = Book.select(string.join([
                term for term in [
                    statusSelect, titleSelect, authorSelect, kindSelect,
                    categorySelect
                ] if term != ""
            ], " AND "),
                                clauseTables=clauseTables)

        results = {}
        i = 1
        for b in books:
            theTitle = b.title.booktitle.decode("unicode_escape")
            if b.notes == None:
                b.notes = ""
            authorString = string.join([
                a.author_name.decode("unicode_escape") for a in b.title.author
            ], ",")
            results[i] = (string.capitalize(theTitle), authorString,
                          b.listprice,
                          b.title.publisher.decode("unicode_escape"),
                          b.status.decode("unicode_escape"), b.title.isbn,
                          b.distributor.decode("unicode_escape"),
                          b.notes.decode("unicode_escape"), b.id,
                          b.title.kind and b.title.kind.kindName or '')
            i = i + 1

        return results
Esempio n. 13
0
 def test_bookedit_functional(self):
     random_item=random.sample(list(Book.select()), 1)[0]
     response=self._my_app.get('/bookedit', {'id':random_item.id})
     code, error=tidylib.tidy_document(response.body, options={'show-errors':1, 'show-warnings':0})
     self.assertFalse(error, '/bookedit did not return valid html page')
Esempio n. 14
0
    def checkout(self,**args):
        self.common()
        self._checkouttemplate.status_from=args.get("status_from","STOCK")
        self._checkouttemplate.status_to=args.get("status_to","RETURNED")
        self._checkouttemplate.schedules = [("list price",1)]+cfg.get("multiple_prices")
        
        if "change" in args:
            return self.addtocart(**args)
        if "finalize" in args:
            schedule_name=args["schedule"]
            schedule=[x for x in cfg.get("multiple_prices")+[("list price",1)] if x[0]==schedule_name] 
            schedule_price=schedule[0][1]
            receipt=""
            for q in cherrypy.session.get('quantities',[]):

                original=q[0]
                howmany=q[1]
                
                for copy in list(Book.select(AND(Book.q.titleID==original.titleID,Book.q.status=="STOCK",Book.q.listprice==original.listprice)))[0:howmany]:
                    cursor=self.conn.cursor()
                    cursor.execute("""
                        INSERT INTO transactionLog SET
                        action = "SALE",
                        amount = %s,
                        cashier = %s,
                        date = NOW(),
                        info = %s,
                        schedule = %s,
                        owner = %s
                        """,(copy.listprice * schedule_price,args["cashier"],"[%s] %s" % (copy.distributor,copy.title.booktitle),schedule_name,copy.owner))
                    copy.sellme()
                    cursor.close()
                line_pt_1 =  "%s  X  %s  @ $%.2f * %i%%" % (original.title.booktitle[:25],howmany,original.listprice,schedule_price * 100)
                receipt=receipt+string.ljust(line_pt_1,50)+string.rjust("$%.2f" % (howmany*schedule_price*original.listprice),10)
            return receipt
        
        if "restatus" in args and "status_to" in args and "status_from" in args:
            for q in cherrypy.session.get('quantities',[]):
                original=q[0]
                howmany=q[1]
                for copy in list(Book.select(AND(Book.q.titleID==original.titleID,Book.q.status==args["status_from"],Book.q.listprice==original.listprice)))[0:howmany]:
                    
                    copy.status=args["status_to"]
                    
            cherrypy.session['quantities']=[]

        if "delete" in args:
            for q in cherrypy.session.get('quantities',[]):
                original=q[0]
                original_price=original.listprice
                original_status=original.status
                original_title_id=original.titleID
                howmany=q[1]
                for copy in list(Book.select(AND(Book.q.titleID==original_title_id,Book.q.status==original_status,Book.q.listprice==original_price)))[0:howmany]:
                    
                    Book.delete(copy.id)
                    
            cherrypy.session['quantities']=[]

            
        
        self._checkouttemplate.quantities=cherrypy.session.get('quantities',[])
        return self._checkouttemplate.respond()
Esempio n. 15
0
def getInventory(queryTerms):
    print(queryTerms, file=sys.stderr)
    keys = list(queryTerms)
    print("keys are ", keys)
    for k in keys:
        if type(queryTerms[k]) == bytes:
            queryTerms[k] = queryTerms[k].decode("utf-8")

    isbnSelect = ""
    kindSelect = ""
    statusSelect = ""
    titleSelect = ""
    authorSelect = ""
    categorySelect = ""
    clauseTables = []

    if "kind" in keys:  # joins suck, avoid if possible
        kind_map = {}
        for k in [(x.kindName, x.id) for x in list(Kind.select())]:
            kind_map[k[0]] = k[1]
        try:
            kind_id = kind_map[queryTerms["kind"]]
            kindSelect = Book.sqlrepr(
                AND(
                    Field("book", "title_id") == Field("title", "id"),
                    Field("title", "kind_id") == kind_id,
                )
            )
        except:
            pass

    if "status" in keys:
        statusSelect = Book.sqlrepr(Field("book", "status") == queryTerms["status"])

    if (
        ("title" in keys)
        or ("authorName" in keys)
        or ("kind" in keys)
        or ("categoryName" in keys)
        or ("isbn" in keys)
    ):
        clauseTables.append("title")
        # we are going to need to do a join

        if "title" in keys:
            titleSelect = Book.sqlrepr(
                AND(
                    Field("book", "title_id") == Field("title", "id"),
                    RLIKE(Field("title", "booktitle"), queryTerms["title"]),
                )
            )

        if "isbn" in keys:
            isbn, price = _process_isbn(queryTerms["isbn"])
            print("isbn and price are ", isbn, price)
            titleSelect = Book.sqlrepr(
                AND(
                    Field("book", "title_id") == Field("title", "id"),
                    Field("title", "isbn") == isbn,
                )
            )

        if "authorName" in keys:
            # authorSelect="""book.title_id = title.id AND author.title_id=title.id AND author.author_name RLIKE %s""" % (Book.sqlrepr(queryTerms["authorName"]))
            authorSelect = Book.sqlrepr(
                AND(
                    Field("book", "title_id") == Field("title", "id"),
                    Field("author", "id") == Field("author_title", "author_id"),
                    Field("title", "id") == Field("author_title", "title_id"),
                    RLIKE(Field("author", "author_name"), queryTerms["authorName"]),
                )
            )
            clauseTables.append("author")
            clauseTables.append("author_title")

        if "categoryName" in keys:
            categorySelect = (
                """book.title_id = title.id AND category.title_id=title.id AND category.category_name RLIKE %s"""
                % (Book.sqlrepr(queryTerms["categoryName"]))
            )
            clauseTables.append("category")
    try:
        books = Book.select(
            " AND ".join(
                [
                    term
                    for term in [
                        statusSelect,
                        titleSelect,
                        authorSelect,
                        kindSelect,
                        categorySelect,
                    ]
                    if term != ""
                ]
            ),
            clauseTables=clauseTables,
            distinct=True,
        )
    except TypeError:
        books = Book.select(
            " AND ".join(
                [
                    term
                    for term in [
                        statusSelect,
                        titleSelect,
                        authorSelect,
                        kindSelect,
                        categorySelect,
                    ]
                    if term != ""
                ]
            ),
            clauseTables=clauseTables,
        )

    results = {}
    i = 1
    for book_for_info in books:
        theTitle = book_for_info.title.booktitle
        authorString = ", ".join([a.authorName for a in book_for_info.title.author])
        categoryString = ", ".join(
            [c.categoryName for c in book_for_info.title.categorys]
        )
        results[i] = (
            theTitle.capitalize(),
            authorString,
            book_for_info.listprice if book_for_info.listprice is not None else "",
            book_for_info.title.publisher
            if book_for_info.title.publisher is not None
            else "",
            book_for_info.status if book_for_info.status is not None else "",
            book_for_info.title.isbn,
            book_for_info.distributor if book_for_info.distributor is not None else "",
            book_for_info.location.locationName
            if book_for_info.location is not None
            else "",
            book_for_info.notes if book_for_info.notes is not None else "",
            book_for_info.id,
            book_for_info.title.kind and book_for_info.title.kind.kindName
            if book_for_info.title.kind is not None
            else "",
            categoryString,
            book_for_info.title.type if book_for_info.title.type is not None else "",
        )
    return results