Esempio n. 1
0
    def _consumption_sections(self, case_stub, case_ledgers,
                              section_timestamp_map):
        case_id = case_stub.case_id
        for section_id, consumption_section_id in self.stock_settings.section_to_consumption_types.items(
        ):
            if section_id in case_ledgers or self.stock_settings.force_consumption_case_filter(
                    case_stub):

                consumption_entries = []
                current_section_sate = case_ledgers.get(section_id, {})
                if self.stock_settings.default_product_list:
                    for product_id in self.stock_settings.default_product_list:
                        state = current_section_sate.get(product_id, None)
                        if not state:
                            try:
                                state = LedgerAccessors(
                                    self.domain_name).get_ledger_value(
                                        case_id, section_id, product_id)
                            except LedgerValueNotFound:
                                pass

                        consumption_entries.append(
                            self._consumption_entry(case_id, product_id,
                                                    state))
                else:
                    for product_id in sorted(current_section_sate.keys()):
                        state = current_section_sate[product_id]
                        consumption_entries.append(
                            self._consumption_entry(case_id, product_id,
                                                    state))

                consumption_entries = [
                    e for e in consumption_entries if e is not None
                ]
                if consumption_entries:
                    yield self.elem_maker.balance(
                        *consumption_entries, **{
                            'entity-id': case_id,
                            'date': section_timestamp_map[section_id],
                            'section-id': consumption_section_id,
                        })
Esempio n. 2
0
    def test_balance_consumption(self):
        initial = float(100)
        initial_amounts = [(p._id, initial) for p in self.products]
        self.submit_xml_form(balance_submission(initial_amounts))

        final_amounts = [(p._id, float(50 - 10*i)) for i, p in enumerate(self.products)]
        self.submit_xml_form(balance_submission(final_amounts))
        for product, amt in final_amounts:
            self.check_product_stock(self.sp, product, amt, 0)
            inferred = amt - initial
            if should_use_sql_backend(self.domain):
                sql_txn = LedgerAccessors(self.domain.name).get_latest_transaction(
                    self.sp.case_id, 'stock', product
                )
                self.assertEqual(inferred, sql_txn.delta)
            else:
                inferred_txn = StockTransaction.objects.get(
                    case_id=self.sp.case_id, product_id=product, subtype=stockconst.TRANSACTION_SUBTYPE_INFERRED
                )
                self.assertEqual(Decimal(str(inferred)), inferred_txn.quantity)
                self.assertEqual(Decimal(str(amt)), inferred_txn.stock_on_hand)
                self.assertEqual(stockconst.TRANSACTION_TYPE_CONSUMPTION, inferred_txn.type)
Esempio n. 3
0
    def test_stock_status_data_source_raw(self):
        ledger_value = LedgerAccessors(self.domain).get_ledger_value(
            self.supply_point.case_id, "stock", self.product._id
        )

        config = {
            'domain': self.domain,
            'aggregate': False,
            'advanced_columns': True,
        }
        self.assertEqual(
            list(StockStatusDataSource(config).get_data()),
            [{
                'category': 'nodata',
                'consumption': None,
                'current_stock': 50,
                'last_reported': ledger_value.last_modified,
                'location_id': self.location.location_id,
                'months_remaining': None,
                'product_id': self.product._id,
                'product_name': self.product.name,
                'resupply_quantity_needed': None}]
        )
Esempio n. 4
0
def compute_daily_consumption(domain,
                              case_id,
                              product_id,
                              window_end,
                              section_id=const.SECTION_TYPE_STOCK,
                              configuration=None):
    """
    Computes the consumption for a product at a supply point.

    Can optionally pass a section_id, but by default the 'stock'
    value is used for computation.

    Returns None if there is insufficient history.
    """
    from corehq.form_processor.interfaces.dbaccessors import LedgerAccessors

    configuration = configuration or ConsumptionConfiguration()
    window_start = window_end - timedelta(days=configuration.max_window)
    transactions = LedgerAccessors(domain).get_transactions_for_consumption(
        case_id, product_id, section_id, window_start, window_end)
    return compute_daily_consumption_from_transactions(transactions,
                                                       window_start,
                                                       configuration)
Esempio n. 5
0
    def test_archive_only_form(self):
        # check no data in stock states
        ledger_accessors = LedgerAccessors(self.domain.name)
        ledger_values = ledger_accessors.get_ledger_values_for_case(self.sp.case_id)
        self.assertEqual(0, len(ledger_values))

        initial_amounts = [(p._id, float(100)) for p in self.products]
        form_id = self.submit_xml_form(balance_submission(initial_amounts))

        # check that we made stuff
        def _assert_initial_state():
            if should_use_sql_backend(self.domain):
                self.assertEqual(3, LedgerTransaction.objects.filter(form_id=form_id).count())
            else:
                self.assertEqual(1, StockReport.objects.filter(form_id=form_id).count())
                self.assertEqual(3, StockTransaction.objects.filter(report__form_id=form_id).count())

            ledger_values = ledger_accessors.get_ledger_values_for_case(self.sp.case_id)
            self.assertEqual(3, len(ledger_values))
            for state in ledger_values:
                self.assertEqual(100, int(state.stock_on_hand))

        _assert_initial_state()

        # archive and confirm commtrack data is cleared
        form = FormAccessors(self.domain.name).get_form(form_id)
        form.archive()
        self.assertEqual(0, len(ledger_accessors.get_ledger_values_for_case(self.sp.case_id)))
        if should_use_sql_backend(self.domain):
            self.assertEqual(0, LedgerTransaction.objects.filter(form_id=form_id).count())
        else:
            self.assertEqual(0, StockReport.objects.filter(form_id=form_id).count())
            self.assertEqual(0, StockTransaction.objects.filter(report__form_id=form_id).count())

        # unarchive and confirm commtrack data is restored
        form.unarchive()
        _assert_initial_state()
 def setUp(self):
     super(TestReprocessDuringSubmission, self).setUp()
     self.factory = CaseFactory(domain=self.domain)
     self.formdb = XFormInstance.objects
     self.ledgerdb = LedgerAccessors(self.domain)
Esempio n. 7
0
    def test_archive_last_form(self):
        initial_amounts = [(p._id, float(100)) for p in self.products]
        self.submit_xml_form(balance_submission(initial_amounts),
                             timestamp=datetime.utcnow() + timedelta(-30))

        final_amounts = [(p._id, float(50))
                         for i, p in enumerate(self.products)]
        second_form_id = self.submit_xml_form(
            balance_submission(final_amounts))

        ledger_accessors = LedgerAccessors(self.domain.name)

        def _assert_initial_state():
            if should_use_sql_backend(self.domain):
                self.assertEqual(
                    3,
                    LedgerTransaction.objects.filter(
                        form_id=second_form_id).count())
            else:
                self.assertEqual(
                    1,
                    StockReport.objects.filter(form_id=second_form_id).count())
                # 6 = 3 stockonhand and 3 inferred consumption txns
                self.assertEqual(
                    6,
                    StockTransaction.objects.filter(
                        report__form_id=second_form_id).count())

            ledger_values = ledger_accessors.get_ledger_values_for_case(
                self.sp.case_id)
            self.assertEqual(3, len(ledger_values))
            for lv in ledger_values:
                self.assertEqual(50, lv.stock_on_hand)
                self.assertEqual(round(float(lv.daily_consumption), 2), 1.67)

        # check initial setup
        _assert_initial_state()

        # archive and confirm commtrack data is deleted
        form = FormAccessors(self.domain.name).get_form(second_form_id)
        with process_kafka_changes('LedgerToElasticsearchPillow'):
            form.archive()

        if should_use_sql_backend(self.domain):
            self.assertEqual(
                0,
                LedgerTransaction.objects.filter(
                    form_id=second_form_id).count())
        else:
            self.assertEqual(
                0,
                StockReport.objects.filter(form_id=second_form_id).count())
            self.assertEqual(
                0,
                StockTransaction.objects.filter(
                    report__form_id=second_form_id).count())

        ledger_values = ledger_accessors.get_ledger_values_for_case(
            self.sp.case_id)
        self.assertEqual(3, len(ledger_values))
        for state in ledger_values:
            # balance should be reverted to 100 in the StockState
            self.assertEqual(100, int(state.stock_on_hand))
            # consumption should be none since there will only be 1 data point
            self.assertIsNone(state.daily_consumption)

        # unarchive and confirm commtrack data is restored
        with process_kafka_changes('LedgerToElasticsearchPillow'):
            form.unarchive()
        _assert_initial_state()
Esempio n. 8
0
                            domain=self.domain.name,
                            **submit_extras)
        return instance_id

    def check_product_stock(self,
                            case,
                            product_id,
                            expected_soh,
                            expected_qty,
                            section_id='stock'):
        if not isinstance(expected_qty, Decimal):
            expected_qty = Decimal(str(expected_qty))
        if not isinstance(expected_soh, Decimal):
            expected_soh = Decimal(str(expected_soh))

        latest_trans = LedgerAccessors(
            self.domain.name).get_latest_transaction(case.case_id, section_id,
                                                     product_id)
        self.assertIsNotNone(latest_trans)
        self.assertEqual(section_id, latest_trans.section_id)
        self.assertEqual(expected_soh, latest_trans.stock_on_hand)

        if should_use_sql_backend(self.domain):
            if latest_trans.type == LedgerTransaction.TYPE_TRANSFER:
                self.assertEqual(int(expected_qty), latest_trans.delta)
        else:
            self.assertEqual(expected_qty, latest_trans.quantity)


class CommTrackBalanceTransferTest(CommTrackSubmissionTest):
    @run_with_all_backends
    def test_balance_submit(self):
Esempio n. 9
0
    for section in generator.yield_sections():
        yield section


class StockPayloadGenerator(object):
    def __init__(self, domain_name, stock_settings, case_stub_list):
        self.domain_name = domain_name
        self.stock_settings = stock_settings
        self.case_stub_list = case_stub_list

        from lxml.builder import ElementMaker
        self.elem_maker = ElementMaker(namespace=COMMTRACK_REPORT_XMLNS)

    def yield_sections(self):
        case_ids = [case.case_id for case in self.case_stub_list]
        all_current_ledgers = LedgerAccessors(self.domain_name).get_current_ledger_state(case_ids)
        for case_stub in self.case_stub_list:
            case_id = case_stub.case_id
            case_ledgers = all_current_ledgers[case_id]

            section_timestamp_map = defaultdict(lambda: json_format_datetime(datetime.utcnow()))
            for section_id in sorted(case_ledgers.keys()):
                state_map = case_ledgers[section_id]
                stock_states = sorted(list(state_map.values()), key=lambda s: s.product_id)
                as_of = json_format_datetime(max(txn.last_modified_date for txn in stock_states))
                section_timestamp_map[section_id] = as_of
                yield self.elem_maker.balance(
                    *(self._state_to_xml(e) for e in stock_states),
                    **{'entity-id': case_id, 'date': as_of, 'section-id': section_id}
                )
Esempio n. 10
0
 def test_transactions(expected):
     state = LedgerAccessors(self.domain).get_current_ledger_state(
         list(self.case_ids))
     for case_id, sections in state.items():
         self._validate_case_data(sections, expected[case_id])
Esempio n. 11
0
 def _get_ledger_state(self, case_id):
     return LedgerAccessors(self.domain_name).get_case_ledger_state(case_id)
 def test_get_case_ledger_state(self):
     for case_id in self.case_ids:
         state = LedgerAccessors(self.domain).get_case_ledger_state(case_id)
         for section, products in state.items():
             for product, state in products.items():
                 self.assertEqual(state.stock_on_hand, self.transactions[case_id][section][product])
Esempio n. 13
0
 def setUp(self):
     super(TestReprocessDuringSubmission, self).setUp()
     self.factory = CaseFactory(domain=self.domain)
     self.formdb = FormAccessors(self.domain)
     self.casedb = CaseAccessors(self.domain)
     self.ledgerdb = LedgerAccessors(self.domain)
 def setUp(self):
     super(ExplodeLedgersTest, self).setUp()
     self.case_accessor = CaseAccessors(self.project.name)
     self.ledger_accessor = LedgerAccessors(self.project.name)
     self._create_ledgers()
Esempio n. 15
0
            date_formatter=date_formatter,
        )
        submit_form_locally(
            instance=instance,
            domain=self.domain.name,
            **submit_extras
        )
        return instance_id

    def check_product_stock(self, case, product_id, expected_soh, expected_qty, section_id='stock'):
        if not isinstance(expected_qty, Decimal):
            expected_qty = Decimal(str(expected_qty))
        if not isinstance(expected_soh, Decimal):
            expected_soh = Decimal(str(expected_soh))

        latest_trans = LedgerAccessors(self.domain.name).get_latest_transaction(
            case.case_id, section_id, product_id
        )
        self.assertIsNotNone(latest_trans)
        self.assertEqual(section_id, latest_trans.section_id)
        self.assertEqual(expected_soh, latest_trans.stock_on_hand)

        if should_use_sql_backend(self.domain):
            if latest_trans.type == LedgerTransaction.TYPE_TRANSFER:
                self.assertEqual(int(expected_qty), latest_trans.delta)
        else:
            self.assertEqual(expected_qty, latest_trans.quantity)


class CommTrackBalanceTransferTest(CommTrackSubmissionTest):
Esempio n. 16
0
        ...
    }

    Note: this only works for the Couch backend
    """
    request_params = request.GET
    case_id = request_params.get('case_id')
    if not case_id:
        return json_response(
            {'message': 'You must specify a case id to make this query.'},
            status_code=400)
    try:
        case = CaseAccessors(domain).get_case(case_id)
    except CaseNotFound:
        raise Http404()
    ledger_map = LedgerAccessors(domain).get_case_ledger_state(case.case_id)

    def custom_json_handler(obj):
        if hasattr(obj, 'stock_on_hand'):
            return obj.stock_on_hand
        return json_handler(obj)

    return json_response(
        {
            'entity_id': case_id,
            'ledger': ledger_map,
        },
        default=custom_json_handler,
    )

Esempio n. 17
0
 def test_transactions(expected):
     for case_id in self.case_ids:
         state = LedgerAccessors(
             self.domain).get_case_ledger_state(case_id)
         self._validate_case_data(state, expected[case_id])