def _test_subtype(self, initial, final):
        case_id = uuid.uuid4().hex
        CommCareCase(
            _id=case_id,
            domain='fakedomain',
        ).save()

        product_id = uuid.uuid4().hex
        SQLProduct(product_id=product_id, domain='fakedomain').save()
        report = StockReport.objects.create(form_id=uuid.uuid4().hex,
                                            date=ago(1),
                                            server_date=datetime.utcnow(),
                                            type=const.REPORT_TYPE_BALANCE)

        txn = StockTransaction(
            report=report,
            section_id=const.SECTION_TYPE_STOCK,
            type=const.TRANSACTION_TYPE_STOCKONHAND,
            subtype=initial,
            case_id=case_id,
            product_id=product_id,
            stock_on_hand=Decimal(10),
        )
        txn.save()

        saved = StockTransaction.objects.get(id=txn.id)
        self.assertEqual(final, saved.subtype)
Beispiel #2
0
    def setUpClass(cls):
        super(TestGetValuesByProduct, cls).setUpClass()
        cls.data = [
            {
                "product": "coke",
                "section": "soh",
                "balance": 32
            },
            {
                "product": "coke",
                "section": "consumption",
                "balance": 63
            },
            {
                "product": "surge",
                "section": "soh",
                "balance": 85
            },
            {
                "product": "fanta",
                "section": "soh",
                "balance": 11
            },
        ]
        product_ids = {p['product'] for p in cls.data}

        SQLProduct.objects.bulk_create([
            SQLProduct(domain=cls.domain_name, product_id=id, code=id)
            for id in product_ids
        ])
Beispiel #3
0
class StockTestBase(TestCase):
    @classmethod
    def setUpClass(cls):
        super(StockTestBase, cls).setUpClass()
        cls.domain = create_domain("stock-report-test")

    @classmethod
    def tearDownClass(cls):
        cls.domain.delete()
        super(StockTestBase, cls).tearDownClass()

    def setUp(self):
        # create case
        case = CaseFactory(domain=self.domain.name).create_case()
        self.case_id = case.case_id

        self.product_id = uuid.uuid4().hex
        SQLProduct(product_id=self.product_id, domain=self.domain.name).save()
        self._stock_report = functools.partial(_stock_report, self.domain.name,
                                               self.case_id, self.product_id)
        self._receipt_report = functools.partial(_receipt_report,
                                                 self.domain.name,
                                                 self.case_id, self.product_id)
        self._test_config = ConsumptionConfiguration.test_config()
        self._compute_consumption = functools.partial(
            compute_daily_consumption,
            self.domain.name,
            self.case_id,
            self.product_id,
            now,
            configuration=self._test_config)
Beispiel #4
0
    def setUp(self):
        super(TestGetValuesByProduct, self).setUp()
        self.ledger_processor = FormProcessorInterface(
            domain=self.domain_name).ledger_processor
        self.domain_obj = create_domain(self.domain_name)
        SQLProduct.objects.bulk_create([
            SQLProduct(domain=self.domain_name,
                       product_id=data['product_id'],
                       code=data['product']) for data in self.data
        ])

        transactions_flat = []
        self.transactions = {}
        for d in self.data:
            product = d['product']
            product_id = d['product_id']
            section = d['section']
            balance = d['balance']
            transactions_flat.append(
                StockTransactionHelper(case_id=self.case_id,
                                       section_id=section,
                                       product_id=product_id,
                                       action='soh',
                                       quantity=balance,
                                       timestamp=datetime.utcnow()))
            self.transactions.setdefault(self.case_id,
                                         {}).setdefault(section,
                                                        {})[product] = balance

        self.new_stock_report, self.form = self.create_report(
            transactions_flat)
        self._create_models_for_stock_report_helper(self.form,
                                                    self.new_stock_report)
Beispiel #5
0
 def handle(self):
     topic = self.args[0].lower()
     if topic == 'stock':
         self.respond(
             "Please send your receipts in the format "
             "' <Commodity code> <stock on hand > . <quantity received>'")
     elif topic == 'reminder':
         if user_needs_reminders(self.user):
             self.respond(DEACTIVATE_REMINDERS)
         else:
             self.respond(REACTIVATE_REMINDERS)
     elif 'code' in topic:
         codes = SQLProduct.by_domain(
             self.domain).order_by('code').values_list('code', flat=True)
         self.respond("Available commodity codes: %(codes)s",
                      codes=", ".join(codes))
     else:
         try:
             sql_product = SQLProduct.objects.get(domain=self.domain,
                                                  code=topic)
             msg = "%s is the commodity code for %s" % (topic,
                                                        sql_product.name)
             if sql_product.units:
                 msg += " (%s)" % sql_product.units
             if sql_product.description and sql_product.description not in sql_product.name:
                 msg += " %s" % sql_product.description
             self.respond(msg)
         except SQLProduct.DoesNotExist:
             self.help()
Beispiel #6
0
    def products(self, value):
        # this will set stocks_all_products to true if the user
        # has added all products in the domain to this location
        self.stocks_all_products = (set(value) == set(
            SQLProduct.by_domain(self.domain)))

        self._products.set(value)
Beispiel #7
0
    def products(self, value):
        # this will set stocks_all_products to true if the user
        # has added all products in the domain to this location
        self.stocks_all_products = (set(value) ==
                                    set(SQLProduct.by_domain(self.domain)))

        self._products = value
Beispiel #8
0
 def products(self):
     """
     If there are no products specified for this location, assume all
     products for the domain are relevant.
     """
     if self.stocks_all_products:
         return SQLProduct.by_domain(self.domain)
     else:
         return self._products.all()
Beispiel #9
0
 def products(self):
     """
     If there are no products specified for this location, assume all
     products for the domain are relevant.
     """
     if self.stocks_all_products:
         return SQLProduct.by_domain(self.domain)
     else:
         return self._products.all()
Beispiel #10
0
    def rows(self):
        def percent(x, y):
            return "%d%% <small>(%d)</small>" % (x * 100 / (y or 1), x)

        def _stock_status(status, loc):
            daily = status.daily_consumption or 0
            state = status.stock_on_hand / ((daily * 30) or 1)
            if state == 0.0:
                return "stockout"
            elif state < loc.location_type.understock_threshold:
                return "adequate"
            elif state < loc.location_type.overstock_threshold + 7:
                return "low"
            else:
                return "overstock"

        locations = self.get_locations(self.config['location_id'], self.config['domain'])

        row_data = {}

        for product in SQLProduct.by_domain(self.domain).exclude(is_archived=True):
            row_data[product.name] = {'total_fac': 0, 'reported_fac': 0,
                                      'stockout': 0, 'low': 0, 'overstock': 0, 'adequate': 0}

        for location in locations:
            location_products = list(location.products)
            stock_states = StockState.objects.filter(
                case_id=location.supply_point_id,
                section_id=STOCK_SECTION_TYPE,
                sql_product__in=location_products
            )

            for product in location_products:
                row_data[product.name]['total_fac'] += 1

            for state in stock_states:
                p_name = state.sql_product.name
                row_data[p_name]['reported_fac'] += 1
                s = _stock_status(state, location)
                row_data[p_name][s] += 1

        rows = []
        for k, v in row_data.iteritems():
            if v['total_fac'] > 0:
                rows.append([
                    k,
                    v['total_fac'],
                    v['reported_fac'],
                    percent(v['stockout'], v['reported_fac']),
                    percent(v['adequate'], v['reported_fac']),
                    percent(v['low'], v['reported_fac']),
                    percent(v['overstock'], v['reported_fac']),
                ])
        return rows
    def setUpClass(cls):
        cls.domain = Domain(name='test')
        cls.domain.save()

        cls.case_id = uuid.uuid4().hex
        CommCareCase(
            _id=cls.case_id,
            domain='fakedomain',
        ).save()

        cls.product_id = uuid.uuid4().hex
        SQLProduct(product_id=cls.product_id).save()
Beispiel #12
0
    def setUpClass(cls):
        super(LogisticsConsumptionTest, cls).setUpClass()
        cls.domain = Domain(name='test')
        cls.domain.save()

        cls.case_id = uuid.uuid4().hex
        CommCareCase(
            _id=cls.case_id,
            domain='fakedomain',
        ).save()

        cls.product_id = uuid.uuid4().hex
        SQLProduct(product_id=cls.product_id, domain='fakedomain').save()
Beispiel #13
0
    def setUp(self):
        # create case
        self.case_id = uuid.uuid4().hex
        CommCareCase(
            _id=self.case_id,
            domain='fakedomain',
        ).save()

        self.product_id = uuid.uuid4().hex
        SQLProduct(product_id=self.product_id).save()
        self._stock_report = functools.partial(_stock_report, self.case_id, self.product_id)
        self._receipt_report = functools.partial(_receipt_report, self.case_id, self.product_id)
        self._test_config = ConsumptionConfiguration.test_config()
        self._compute_consumption = functools.partial(compute_daily_consumption, self.case_id,
                                                      self.product_id, now, configuration=self._test_config)
Beispiel #14
0
 def handle(self):
     topic = self.args[0].lower()
     if topic == 'stock':
         self.respond("Please send your receipts in the format "
                      "' <Commodity code> <stock on hand > . <quantity received>'")
     elif topic == 'stop':
         self.respond("Text 'stop' to stop receiving text message reminders.")
     elif topic == 'start':
         self.respond("Text 'start' to get text message reminders every week to submit your stock reports.")
     elif 'code' in topic:
         codes = SQLProduct.by_domain(self.domain).order_by('code').values_list('code', flat=True)
         self.respond("Available commodity codes: %(codes)s", codes=", ".join(codes))
     else:
         try:
             sql_product = SQLProduct.objects.get(domain=self.domain, code=topic)
             msg = "%s is the commodity code for %s" % (topic, sql_product.name)
             if sql_product.units:
                 msg += " (%s)" % sql_product.units
             if sql_product.description and sql_product.description not in sql_product.name:
                 msg += " %s" % sql_product.description
             self.respond(msg)
         except SQLProduct.DoesNotExist:
             self.help()
Beispiel #15
0
 def handle(self):
     topic = self.args[0].lower()
     if topic == 'stock':
         self.respond("Please send your receipts in the format "
                      "' <Commodity code> <stock on hand > . <quantity received>'")
     elif topic == 'reminder':
         if user_needs_reminders(self.user):
             self.respond(DEACTIVATE_REMINDERS)
         else:
             self.respond(REACTIVATE_REMINDERS)
     elif 'code' in topic:
         codes = SQLProduct.by_domain(self.domain).order_by('code').values_list('code', flat=True)
         self.respond("Available commodity codes: %(codes)s", codes=", ".join(codes))
     else:
         try:
             sql_product = SQLProduct.objects.get(domain=self.domain, code=topic)
             msg = "%s is the commodity code for %s" % (topic, sql_product.name)
             if sql_product.units:
                 msg += " (%s)" % sql_product.units
             if sql_product.description and sql_product.description not in sql_product.name:
                 msg += " %s" % sql_product.description
             self.respond(msg)
         except SQLProduct.DoesNotExist:
             self.help()
Beispiel #16
0
 def get_products(self):
     """
     If there are no products specified for this location, assume all
     products for the domain are relevant.
     """
     return self.products.all() or SQLProduct.by_domain(self.domain)
Beispiel #17
0
 def all_products(self):
     return [(p.product_id, p.name)
             for p in SQLProduct.by_domain(self.domain)]
Beispiel #18
0
 def all_products(self):
     return [(p.product_id, p.name)
             for p in SQLProduct.by_domain(self.domain)]
Beispiel #19
0
    def rows(self):
        def percent(x, y):
            return "%d%% <small>(%d)</small>" % (x * 100 / (y or 1), x)

        def _stock_status(transaction, daily_consumption, loc):
            state = transaction.stock_on_hand / ((daily_consumption * 30) or 1)
            if state == 0.0:
                return "stockout"
            elif state < loc.location_type.understock_threshold:
                return "adequate"
            elif state < loc.location_type.overstock_threshold + 7:
                return "low"
            else:
                return "overstock"

        locations = self.get_locations(self.config['location_id'],
                                       self.config['domain'])

        row_data = {}

        for product in SQLProduct.by_domain(
                self.domain).exclude(is_archived=True):
            row_data[product.name] = {
                'total_fac': 0,
                'reported_fac': 0,
                'stockout': 0,
                'low': 0,
                'overstock': 0,
                'adequate': 0
            }

        transactions = self._last_transaction_for_product_in_period()
        stock_states = StockState.objects.filter(
            sql_location__in=locations).values_list('case_id', 'product_id',
                                                    'daily_consumption')

        location_product_to_consumption = {
            (case_id, product_id): daily_consumption or 0
            for case_id, product_id, daily_consumption in stock_states
        }

        for location in locations:
            location_products = list(
                location.products.exclude(is_archived=True))

            for product in location_products:
                row_data[product.name]['total_fac'] += 1

            for transaction in transactions.get(location.supply_point_id, []):
                sql_product = transaction.sql_product
                if sql_product not in location_products:
                    continue
                p_name = sql_product.name
                row_data[p_name]['reported_fac'] += 1
                daily_consumption = location_product_to_consumption.get(
                    (location.supply_point_id, transaction.product_id), 0)
                s = _stock_status(transaction, daily_consumption, location)
                row_data[p_name][s] += 1

        rows = []
        for k, v in six.iteritems(row_data):
            if v['total_fac'] > 0:
                rows.append([
                    k,
                    v['total_fac'],
                    v['reported_fac'],
                    percent(v['stockout'], v['reported_fac']),
                    percent(v['adequate'], v['reported_fac']),
                    percent(v['low'], v['reported_fac']),
                    percent(v['overstock'], v['reported_fac']),
                ])
        return rows
Beispiel #20
0
    def rows(self):
        def percent(x, y):
            return "%d%% <small>(%d)</small>" % (x * 100 / (y or 1), x)

        def _stock_status(transaction, daily_consumption, loc):
            state = transaction.stock_on_hand / ((daily_consumption * 30) or 1)
            if state == 0.0:
                return "stockout"
            elif state < loc.location_type.understock_threshold:
                return "adequate"
            elif state < loc.location_type.overstock_threshold + 7:
                return "low"
            else:
                return "overstock"

        locations = self.get_locations(self.config['location_id'], self.config['domain'])

        row_data = {}

        for product in SQLProduct.by_domain(self.domain).exclude(is_archived=True):
            row_data[product.name] = {'total_fac': 0, 'reported_fac': 0,
                                      'stockout': 0, 'low': 0, 'overstock': 0, 'adequate': 0}

        transactions = self._last_transaction_for_product_in_period()
        stock_states = StockState.objects.filter(
            sql_location__in=locations
        ).values_list('case_id', 'product_id', 'daily_consumption')

        location_product_to_consumption = {
            (case_id, product_id): daily_consumption or 0
            for case_id, product_id, daily_consumption in stock_states
        }

        for location in locations:
            location_products = list(location.products.exclude(is_archived=True))

            for product in location_products:
                row_data[product.name]['total_fac'] += 1

            for transaction in transactions.get(location.supply_point_id, []):
                sql_product = transaction.sql_product
                if sql_product not in location_products:
                    continue
                p_name = sql_product.name
                row_data[p_name]['reported_fac'] += 1
                daily_consumption = location_product_to_consumption.get(
                    (location.supply_point_id, transaction.product_id), 0
                )
                s = _stock_status(transaction, daily_consumption, location)
                row_data[p_name][s] += 1

        rows = []
        for k, v in six.iteritems(row_data):
            if v['total_fac'] > 0:
                rows.append([
                    k,
                    v['total_fac'],
                    v['reported_fac'],
                    percent(v['stockout'], v['reported_fac']),
                    percent(v['adequate'], v['reported_fac']),
                    percent(v['low'], v['reported_fac']),
                    percent(v['overstock'], v['reported_fac']),
                ])
        return rows