コード例 #1
0
        def do_post_create_item(self):
            post_data = get_raw_post_data(self)
            item_dict = parse_json(post_data)

            # Pull out all of the fields we need
            identifier = get_value(item_dict, 'identifier')
            price = parse_float(get_value(item_dict, 'price', 0))
            billing_method = get_value(item_dict, 'billing_method', '')
            special = get_value(item_dict, 'special')

            # Ensure that all necessary data is present
            msg = ''
            if identifier is None or identifier == '':
                msg += 'Must provide identifier. '
            if price is None or price <= 0:
                msg += 'Must provide price and must be positive. '

            if msg != '':
                set_response(self, 400, msg, 'text/text')
            else:
                # Check to see if the provided special is valid
                if special is not None:
                    msg = validate_special(special, billing_method)
                if msg != '':
                    set_response(self, 400, msg, 'text/text')
                else:
                    # Create and store the item and tell the user everything is fine
                    item = Item(identifier, price, billing_method, special)
                    datastore.set('itemdetails:' + item.identifier, item)
                    set_response(self, 200, '')
コード例 #2
0
    def calculate_best_savings(self, applied_to_item, items, datastore):
        item = datastore.get('itemdetails:' +
                             get_value(applied_to_item, 'identifier'))

        # How many items are involved in each application of this special
        chunk_size = self.quantity

        # If the number of items you have to buy is greater than the limit,
        # there is no way this special can apply to anything
        if self.limit is not None and chunk_size > self.limit:
            return (0, [])

        quantity = get_value(applied_to_item, 'quantity', 0)
        # If the customer hasn't bought the minimum quantity, there is no
        # way there can be any savings
        if quantity < chunk_size:
            return (0, [])

        # If the quantity the customer is buying is more than the limit for
        # the special, just decrease the quantity that the special will be
        # applied to
        if self.limit is not None and quantity > self.limit:
            quantity = self.limit

        # How many applications of this special can there be?
        chunks = math.floor(quantity / chunk_size)

        # Return the original price minus the price with discounts
        savings = (chunks * chunk_size * item.price) - (chunks * self.price)
        return (round(savings, 2), [{
            'identifier': item.identifier,
            'quantity': chunks * chunk_size
        }])
コード例 #3
0
        def do_post_add_item_to_order(self):
            post_data = get_raw_post_data(self)
            post_dict = parse_json(post_data)
            order_id = get_value(post_dict, 'order_id')
            item_identifier = get_value(post_dict, 'item_identifier')

            msg = ''
            if order_id is None or order_id == '':
                msg += 'Must provide order_id. '
            if item_identifier is None:
                msg += 'Must provide item. '

            if msg != '':
                set_response(self, 400, msg, 'text/text')
            else:
                order = datastore.get('orders:' + order_id)
                item = datastore.get('itemdetails:' + item_identifier)

                if order is None:
                    set_response(self, 400, 'Order does not exist.',
                                 'text/text')
                elif item is None:
                    set_response(self, 400, 'Item does not exist.',
                                 'text/text')
                else:
                    # If the item is a UNIT type, we only want to allow integers
                    # for the quantity since it doesn't make sense to have something
                    # like 1.25 cans of soup
                    quantity = parse_float(get_value(post_dict, 'quantity'),
                                           1.0)
                    if item.billing_method == Methods.UNIT:
                        quantity = parse_int(quantity)

                    order.add_item(item, quantity)
                    set_response(self, 200, '')
コード例 #4
0
        def do_post_data_store(self):
            post_data = get_raw_post_data(self)
            post_dict = parse_json(post_data)
            key = get_value(post_dict, 'key')
            value = get_value(post_dict, 'value')

            if key is None:
                set_response(self, 400, 'Must provide key', 'text/text')
            elif value is None:
                set_response(self, 400, 'Must provide value', 'text/text')
            else:
                datastore.set(key, value)
                set_response(self, 200, '')
コード例 #5
0
        def calculate_total_with_specials_greedy(self):
            savings = 0.00

            # Create a copy of self.items so we don't have to worry about
            # modifying it
            items_copy = copy.deepcopy(self.items)

            # Want to continue this greedy algorithm until there are no more
            # specials left to yield savings
            while has_specials(items_copy, datastore):
                best_special_savings = 0.00
                best_special_consumed = []

                # Find the special that will save the customer the most money
                for item, quantity in items_copy.items():
                    item_def = datastore.get('itemdetails:' + item)
                    if item_def.special is not None:
                        (savings, items_consumed
                         ) = item_def.special.calculate_best_savings(
                             {
                                 'identifier': item,
                                 'quantity': quantity
                             }, items_copy, datastore)

                        # Check to see if the current special would give the customer
                        # the greatest savings
                        if savings > best_special_savings:
                            best_special_savings = savings
                            best_special_consumed = items_consumed

                # If there was no special that saved the customer money, then
                # there are no more specials that can be applied and we are done
                if best_special_savings == 0.00:
                    break

                # Remove all items that were consumed by the best special
                for item_consumed in best_special_consumed:
                    consumed_name = get_value(item_consumed, 'identifier')
                    items_copy[consumed_name] -= get_value(
                        item_consumed, 'quantity')
                    # If all of this item has been consumed by specials, remove it from the
                    # possible items to consume or be used in the future
                    if items_copy[consumed_name] == 0:
                        del items_copy[consumed_name]

                # Increment the savings by the quantity that the best special saved
                savings += best_special_savings

            return round(self.calculate_total_no_specials() - savings, 2)
コード例 #6
0
 def test_post_create_item_when_given_no_billing_method_defaults_to_unit(self):
     post_data = {'identifier': 'cherries', 'price': 1.00}
     r = requests.post(baseurl + '/createitem', data=json.dumps(post_data))
     self.assertEqual(r.status_code, 200)
     r = requests.get(baseurl + '/getitem?identifier=cherries')
     item = json.loads(r.text)
     self.assertEqual(get_value(item, 'billing_method'), 'unit')
コード例 #7
0
 def do_get_order(self):
     url_query = parse_url_query(self.path)
     order_id = get_value(url_query, 'id')
     if order_id is None or order_id == '':
         set_response(self, 400, 'Must provide order id')
     else:
         order = datastore.get('orders:' + order_id)
         if order is None:
             set_response(self, 400, 'Order does not exist.')
         else:
             set_response(self, 200, order.to_json())
コード例 #8
0
 def remove_item(self, item, removed_quantity):
     # Get the quantity we currently are holding for this order
     current_quantity = get_value(self.items, item.identifier, 0)
     # Remove the desired quantity
     new_quantity = current_quantity - removed_quantity
     # It doesn't make sense to have a zero or negative quantity of items
     # so if the value goes negative or is 0, we want to delete the item
     # from the order
     if new_quantity <= 0:
         del self.items[item.identifier]
     else:
         self.items[item.identifier] = new_quantity
コード例 #9
0
    def calculate_best_savings(self, applied_to_item, items, datastore):
        # Get the item definition and the value that the other item must be
        # equal to or less than in cost
        item_def = datastore.get('itemdetails:' + get_value(applied_to_item, 'identifier'))
        max_cost = get_value(applied_to_item, 'quantity') * item_def.price

        # Find the highest cost item that is less than or equal to the max_cost
        best_cost = 0
        best_item = None
        for item, quantity in items.items():
            # Skip the item we're applying the special to
            if item == item_def.identifier:
                continue

            # Get the definition for the item we're currently looking at
            current_item_def = datastore.get('itemdetails:' + item)

            # Determine if it's better than any previous item we've seen
            # We can allow weighted items, but if we do the special must consume the
            # entire weight
            if current_item_def.billing_method.value == 'weight':
                cost = current_item_def.price * quantity
                if current_item_def.price * quantity <= max_cost and cost > best_cost:
                    best_cost = cost
                    best_item = {'identifier': item, 'quantity': quantity}
            elif current_item_def.billing_method.value == 'unit':
                if current_item_def.price <= max_cost and current_item_def.price > best_cost:
                    best_cost = current_item_def.price
                    best_item = {'identifier': item, 'quantity': 1}

        # Calculate the savings and build the list of consumed items
        savings = self.off/100 * best_cost
        consumed_items = []
        if best_item is not None:
            consumed_items.append(best_item)
            consumed_items.append({'identifier': item_def.identifier, 'quantity': get_value(applied_to_item, 'quantity')})

        return (round(savings, 2), consumed_items)
コード例 #10
0
        def do_delete_order(self):
            post_data = get_raw_post_data(self)
            post_dict = parse_json(post_data)
            order_id = get_value(post_dict, 'id')

            if order_id is None:
                set_response(self, 400, 'Must provide id.', 'text/text')
            else:
                if datastore.get('orders:' + order_id) is not None:
                    datastore.delete('orders:' + order_id)
                    set_response(self, 200, '')
                else:
                    set_response(self, 400, 'Order does not exist',
                                 'text/text')
コード例 #11
0
 def do_get_item(self):
     url_query = parse_url_query(self.path)
     identifier = get_value(url_query, 'identifier')
     # Ensure that the client provided an identifier to look up
     if identifier is None or identifier == '':
         set_response(self, 400, 'Must provide identifier.',
                      'text/text')
     else:
         item = datastore.get('itemdetails:' + identifier, None)
         if item is not None:
             # Return the item to the user as json
             set_response(self, 200, item.to_json())
         else:
             # If the identifier isn't an identifier from an item, tell the client there
             # was a problem
             set_response(self, 400, 'Item does not exist.',
                          'text/text')
コード例 #12
0
 def do_post_create_order(self):
     post_data = get_raw_post_data(self)
     post_dict = parse_json(post_data)
     order_id = get_value(post_dict, 'id')
     # Ensure the client provided an id to create
     if order_id is None or order_id == '':
         set_response(self, 400, 'Must provide id.', 'text/text')
     else:
         # If the order already exists, we don't want to overwrite it
         # Instead, tell the user that there was a problem
         if datastore.get('orders:' + order_id) is None:
             order = MakeOrder(order_id, datastore)
             datastore.set('orders:' + order_id, order)
             set_response(self, 200, '')
         else:
             set_response(self, 400,
                          'Order with that id already exists.',
                          'text/text')
コード例 #13
0
 def test_get_value_when_key_not_in_dict_return_default(self):
     d = {'test': 'value'}
     self.assertEqual(H.get_value(d, 'key', 'test_default'),
                      'test_default')
コード例 #14
0
        def calculate_total_with_specials_optimal(self):
            max_savings = 0.00

            # Get all permutations of special items and a list of the remaining items that don't
            # have specials
            (specials_perms, non_special_items
             ) = self.get_special_permutations_and_remainder_items()

            # Iterate over each permutation to see which special application order
            # yields the most savings
            for special_perm_instance in specials_perms:
                instance_savings = 0.00

                # Convert the tuple into a list of items
                special_perm_instance = list(special_perm_instance)
                # Compute the current item list instance
                instance_items = flatten(special_perm_instance,
                                         non_special_items)
                instance_items_dict = merge_item_dict_lists_to_dict(
                    special_perm_instance, non_special_items)

                # We want to use the list to iterate over because it ensures order
                # whereas the dict does not. This will calculate the quantity saved by
                # a given special permutation
                for item_dict in instance_items:
                    item = get_value(item_dict, 'identifier')
                    quantity = get_value(instance_items_dict, item)

                    # The item must have been fully consumed already and cannot be
                    # considered anymore
                    if quantity is None or quantity == 0:
                        # coverage code analysis program says this line
                        # doesn't run, but putting a print statement in here
                        # and running the tests shows that it does run
                        continue

                    # Get the current item's definition
                    item_def = datastore.get('itemdetails:' + item)

                    # Only compute savings for the special if the item has a special
                    if item_def.special is not None:
                        # Find the quantity the customer can save from this item's special
                        # and which items are involved in the special
                        (new_savings, items_consumed
                         ) = item_def.special.calculate_best_savings(
                             {
                                 'identifier': item,
                                 'quantity': quantity
                             }, instance_items_dict, datastore)

                        # Account for the savings
                        instance_savings += new_savings
                        # Remove any consumed items from the instance item dict
                        for item_consumed in items_consumed:
                            consumed_name = get_value(item_consumed,
                                                      'identifier')
                            instance_items_dict[consumed_name] -= get_value(
                                item_consumed, 'quantity')
                            # If all of this item has been consumed by specials, remove it from the
                            # possible items to consume or be used in the future
                            if instance_items_dict[consumed_name] == 0:
                                del instance_items_dict[consumed_name]

                # Update the maximum savings if this instance saved the customer the most money
                if instance_savings > max_savings:
                    max_savings = instance_savings

            # Return the original order total minus the savings
            return round(self.calculate_total_no_specials() - max_savings, 2)
コード例 #15
0
 def test_get_value_when_dict_is_empty_return_none(self):
     d = {}
     self.assertEqual(H.get_value(d, 'key'), None)
コード例 #16
0
 def test_get_value_when_key_not_in_dict_return_none(self):
     d = {'test': 'value'}
     self.assertEqual(H.get_value(d, 'key'), None)
コード例 #17
0
 def test_get_value_when_key_in_dict_return_value(self):
     d = {'test': 'value'}
     self.assertEqual(H.get_value(d, 'test'), 'value')
コード例 #18
0
    def __init__(self, identifier, price, billing_method, special):
        self.identifier = identifier
        self.price = price
        if billing_method.lower() == 'weight':
            self.billing_method = Methods.WEIGHT
        else:
            # Default to price per item scanned
            self.billing_method = Methods.UNIT
        # Default the special to none
        self.special = None

        # Parse the special out based on its type. The validity of
        # the special has already been verified
        special_type = get_value(special, 'type')
        if special_type == 'AforB':
            buy = get_value(special, 'buy')
            limit = parse_int(get_value(special, 'limit'), None)
            quantity = parse_float(get_value(special, 'for'), 0.0)
            self.special = AforB(buy, quantity, limit)
        elif special_type == 'buyAgetBforCoff':
            buy = get_value(special, 'buy')
            get = get_value(special, 'get')
            off = parse_float(get_value(special, 'off'), 0.0)
            limit = parse_int(get_value(special, 'limit'), None)
            self.special = BuyAgetBforCoff(buy, get, off, limit)
        elif special_type == 'getEOLforAoff':
            off = parse_float(get_value(special, 'off'), 0.0)
            self.special = GetEOLforAoff(off)
        elif special_type == 'markdown':
            price = parse_float(get_value(special, 'price'), 0.0)
            limit = parse_int(get_value(special, 'limit'), None)
            self.special = Markdown(price, limit)
コード例 #19
0
 def get(self, k, default=None):
     return get_value(self.database, k, default)
コード例 #20
0
 def test_get_value_when_value_is_list_returns_the_list(self):
     d = {'test': ['value', 'list', 123]}
     self.assertEqual(H.get_value(d, 'test'), ['value', 'list', 123])
コード例 #21
0
 def test_get_value_when_key_is_in_dict_dont_return_default_if_set(
         self):
     d = {'test': 'entry'}
     self.assertNotEqual(H.get_value(d, 'test', 123), 123)
コード例 #22
0
 def delete(self, k):
     if get_value(self.database, k) is not None:
         del self.database[k]
コード例 #23
0
 def add_item(self, item, added_quantity):
     # Get the quantity we currently are holding for this order
     current_quantity = get_value(self.items, item.identifier, 0)
     self.items[item.identifier] = current_quantity + added_quantity