def test_process_sites(sess):
    site_code = "109"
    Site.insert(sess, site_code, "A Site")
    report_run = ReportRun.insert(sess, "asset", None, "asset", {})
    sess.commit()

    asset_str = "\n".join(("code,,,status", ))
    file_like = StringIO(asset_str)
    output = StringIO()
    writer = csv.writer(output, lineterminator="\n")
    props = {"asset_comparison": {"ignore_site_codes": []}}

    _process_sites(sess, file_like, writer, props, report_run.id)

    assert output.getvalue() == "site_code,asset_status,chellow_status\n"
Пример #2
0
def test_process_sites(sess):
    site_code = "109"
    Site.insert(sess, site_code, "A Site")
    sess.commit()

    asset_str = "\n".join(("code,,,status", ))
    file_like = StringIO(asset_str)
    output = StringIO()
    writer = csv.writer(output, lineterminator="\n")
    props = {"asset_comparison": {"ignore_site_codes": []}}

    _process_sites(sess, file_like, writer, props)

    assert output.getvalue(
    ) == "Site Code,Asset Status,Chellow Status,Problem\n"
Пример #3
0
def content(start_date, finish_date, site_id, typ, user):
    sess = f = writer = None
    try:
        sess = Session()
        running_name, finished_name = chellow.dloads.make_names(
            "site_hh_data_" + start_date.strftime("%Y%m%d%H%M") + ".csv", user)
        f = open(running_name, mode='w', newline='')
        writer = csv.writer(f, lineterminator='\n')
        writer.writerow(
            ('Site Code', 'Type', 'Date') + tuple(map(str, range(1, 49))))
        site = Site.get_by_id(sess, site_id)
        line = None
        for hh in site.hh_data(sess, start_date, finish_date):
            hh_start = hh['start_date']
            if (hh_start.hour, hh_start.minute) == (0, 0):
                if line is not None:
                    writer.writerow(line)
                line = [site.code, typ, hh_start.strftime("%Y-%m-%d")]
            line.append(str(hh[typ]))
        if line is not None:
            writer.writerow(line)
    except:
        msg = traceback.format_exc()
        sys.stderr.write(msg)
        writer.writerow([msg])
    finally:
        if sess is not None:
            sess.close()
        if f is not None:
            f.close()
            os.rename(running_name, finished_name)
Пример #4
0
def content(start_date, finish_date, site_id, typ, user):
    sess = f = writer = None
    try:
        sess = Session()
        running_name, finished_name = chellow.dloads.make_names(
            "site_hh_data_" + to_ct(start_date).strftime("%Y%m%d%H%M") +
            ".csv", user)
        f = open(running_name, mode="w", newline="")
        writer = csv.writer(f, lineterminator="\n")
        writer.writerow(("Site Code", "Type", "HH Start Clock-Time") +
                        tuple(map(str, range(1, 51))))
        site = Site.get_by_id(sess, site_id)
        line = None
        for hh in site.hh_data(sess, start_date, finish_date):
            hh_start_ct = to_ct(hh["start_date"])
            if (hh_start_ct.hour, hh_start_ct.minute) == (0, 0):
                if line is not None:
                    writer.writerow(line)
                line = [site.code, typ, hh_start_ct.strftime("%Y-%m-%d")]
            line.append(str(hh[typ]))
        if line is not None:
            writer.writerow(line)
    except BaseException:
        msg = traceback.format_exc()
        sys.stderr.write(msg)
        writer.writerow([msg])
    finally:
        if sess is not None:
            sess.close()
        if f is not None:
            f.close()
            os.rename(running_name, finished_name)
Пример #5
0
def test_with_scenario(mocker, sess, client):
    mock_Thread = mocker.patch("chellow.reports.report_247.threading.Thread")

    properties = """{
      "scenario_start_year": 2009,
      "scenario_start_month": 8,
      "scenario_duration": 1,

      "era_maps": {
        2000-08-01T00:00:00Z: {
          "llfcs": {
            "22": {
              "new_export": "521"
            }
          },
          "supplier_contracts": {
            "new_export": 10
          }
        }
      },

      "hh_data": {
        "CI017": {
          "generated": "
                2009-08-01 00:00, 40
                2009-08-15 00:00, 40"
        }
      }
    }"""
    scenario_props = loads(properties)
    scenario = Scenario.insert(sess, "New Gen", scenario_props)
    sess.commit()

    now = utc_datetime(2020, 1, 1)
    mocker.patch("chellow.reports.report_247.utc_datetime_now",
                 return_value=now)

    site_code = "CI017"
    site = Site.insert(sess, site_code, "Water Works")

    data = {
        "site_id": site.id,
        "scenario_id": scenario.id,
        "compression": False,
    }

    response = client.post("/reports/247", data=data)

    match(response, 303)

    base_name = ["New Gen"]
    args = scenario_props, base_name, site.id, None, None, False, [], now

    mock_Thread.assert_called_with(target=content, args=args)
Пример #6
0
def long_process(start_date, finish_date, st_id, months, year, month, user):
    caches = {}
    tmp_file = sess = None
    try:
        sess = Session()
        if st_id is None:
            st = None
            base_name = "site_monthly_duration_for_all_site_for_" + \
                str(months) + "_to_" + str(year) + "_" + str(month) + ".csv"
        else:
            st = Site.get_by_id(sess, st_id)
            base_name = "site_monthly_duration_for_" + st.code + "_" + \
                str(months) + "_to_" + str(year) + "_" + str(month) + ".csv"
        running_name, finished_name = chellow.dloads.make_names(
            base_name, user)
        tmp_file = open(running_name, "w")

        forecast_date = chellow.computer.forecast_date()

        tmp_file.write(
            "Site Id,Site Name,Associated Site Ids,Sources,"
            "Generator Types,Month,Metered Imported kWh,"
            "Metered Displaced kWh,Metered Exported kWh,Metered Used kWh,"
            "Metered Parasitic kWh,Metered Generated kWh,"
            "Metered 3rd Party Import kWh,Metered 3rd Party Export kWh,"
            "Metered Imported GBP,Metered Displaced GBP,Metered Exported GBP,"
            "Metered Used GBP,Metered 3rd Party Import GBP,"
            "Billed Imported kWh,Billed Imported GBP,Metering Type,Problem")

        for i in range(months):
            sites = sess.query(Site).order_by(Site.code)
            if st is not None:
                sites = sites.filter(Site.id == st.id)
            for site in sites:
                month_start = start_date + relativedelta(months=i)
                month_finish = month_start + relativedelta(months=1) - HH
                tmp_file.write(
                    '\r\n' + ','.join(
                        '"' + str(value) + '"' for value in process_site(
                            sess, site, month_start, month_finish,
                            forecast_date, tmp_file, start_date, finish_date,
                            caches)))
                tmp_file.flush()

    except:
        msg = traceback.format_exc()
        sys.stderr.write(msg + '\n')
        tmp_file.write("Problem " + msg)
    finally:
        if sess is not None:
            sess.close()
        tmp_file.close()
        os.rename(running_name, finished_name)
Пример #7
0
def content(start_date, finish_date, site_id, typ, sess):
    try:
        site = Site.get_by_id(sess, site_id)
        yield ','.join(
            ('Site Code', 'Type', 'Date') + tuple(map(str, range(1, 49))))
        for group in site.groups(sess, start_date, finish_date, True):
            for hh in group.hh_data(sess):
                hh_start = hh['start_date']
                if (hh_start.hour, hh_start.minute) == (0, 0):
                    yield '\r\n' + ','.join(
                        (site.code, typ, hh_start.strftime("%Y-%m-%d")))
                yield "," + str(hh[typ])
    except:
        yield traceback.format_exc()
Пример #8
0
def test_https_handler(mocker, sess):
    site = Site.insert(sess, "CI017", "Water Works")

    market_role_Z = MarketRole.insert(sess, "Z", "Non-core")
    participant = Participant.insert(sess, "CALB", "AK Industries")
    participant.insert_party(sess, market_role_Z, "None core",
                             utc_datetime(2000, 1, 1), None, None)
    market_role_X = MarketRole.insert(sess, "X", "Supplier")
    market_role_M = MarketRole.insert(sess, "M", "Mop")
    market_role_C = MarketRole.insert(sess, "C", "HH Dc")
    market_role_R = MarketRole.insert(sess, "R", "Distributor")
    participant.insert_party(sess, market_role_M, "Fusion Mop Ltd",
                             utc_datetime(2000, 1, 1), None, None)
    participant.insert_party(sess, market_role_X, "Fusion Ltc",
                             utc_datetime(2000, 1, 1), None, None)
    participant.insert_party(sess, market_role_C, "Fusion DC",
                             utc_datetime(2000, 1, 1), None, None)
    mop_contract = Contract.insert_mop(sess, "Fusion", participant, "", {},
                                       utc_datetime(2000, 1, 1), None, {})
    dc_contract = Contract.insert_hhdc(sess, "Fusion DC 2000", participant, "",
                                       {}, utc_datetime(2000, 1, 1), None, {})
    pc = Pc.insert(sess, "00", "hh", utc_datetime(2000, 1, 1), None)
    insert_cops(sess)
    cop = Cop.get_by_code(sess, "5")
    imp_supplier_contract = Contract.insert_supplier(
        sess,
        "Fusion Supplier 2000",
        participant,
        "",
        {},
        utc_datetime(2000, 1, 1),
        None,
        {},
    )
    dno = participant.insert_party(sess, market_role_R, "WPD",
                                   utc_datetime(2000, 1, 1), None, "22")
    meter_type = MeterType.insert(sess, "C5", "COP 1-5",
                                  utc_datetime(2000, 1, 1), None)
    meter_payment_type = MeterPaymentType.insert(sess, "CR", "Credit",
                                                 utc_datetime(1996, 1, 1),
                                                 None)
    Mtc.insert(
        sess,
        None,
        "845",
        "HH COP5 And Above With Comms",
        False,
        False,
        True,
        meter_type,
        meter_payment_type,
        0,
        utc_datetime(1996, 1, 1),
        None,
    )
    insert_voltage_levels(sess)
    voltage_level = VoltageLevel.get_by_code(sess, "HV")
    dno.insert_llfc(
        sess,
        "510",
        "PC 5-8 & HH HV",
        voltage_level,
        False,
        True,
        utc_datetime(1996, 1, 1),
        None,
    )
    dno.insert_llfc(
        sess,
        "521",
        "Export (HV)",
        voltage_level,
        False,
        False,
        utc_datetime(1996, 1, 1),
        None,
    )
    insert_sources(sess)
    source = Source.get_by_code(sess, "net")
    insert_energisation_statuses(sess)
    energisation_status = EnergisationStatus.get_by_code(sess, "E")
    gsp_group = GspGroup.insert(sess, "_L", "South Western")
    supply = site.insert_e_supply(
        sess,
        source,
        None,
        "Bob",
        utc_datetime(2000, 1, 1),
        None,
        gsp_group,
        mop_contract,
        "773",
        dc_contract,
        "ghyy3",
        "hgjeyhuw",
        pc,
        "845",
        cop,
        None,
        energisation_status,
        {},
        "22 7867 6232 781",
        "510",
        imp_supplier_contract,
        "7748",
        361,
        None,
        None,
        None,
        None,
        None,
    )
    era = supply.eras[0]
    era.insert_channel(sess, True, "ACTIVE")

    sess.commit()

    mock_requests = mocker.patch("chellow.hh_importer.requests")
    mock_response = mocker.Mock()
    mock_requests.get.return_value = mock_response
    mock_response.json.return_value = {
        "DataPoints": [{
            "Flags": 0,
            "Time": 636188256000000000,
            "Value": 21
        }]
    }

    log = []

    def log_f(msg):
        log.append(msg)

    properties = {
        "enabled":
        True,
        "protocol":
        "https",
        "download_days":
        8,
        "url_template":
        "https://example.com/?from="
        "{{chunk_start.strftime('%d/%m/%Y')}}&to="
        "{{chunk_finish.strftime('%d/%m/%Y')}}",
        "url_values": {
            "22 7907 4116 080": {
                "api_key": "768234ht"
            }
        },
    }

    now = utc_datetime(2020, 12, 22)

    https_handler(sess, log_f, properties, dc_contract, now=now)
    expected_log = [
        "Window start: 2020-12-14 00:00",
        "Window finish: 2020-12-21 23:30",
        "Looking at MPAN core 22 7867 6232 781.",
        "Retrieving data from "
        "https://example.com/?from=14/12/2020&to=21/12/2020.",
        "Finished loading.",
    ]
    assert log == expected_log
Пример #9
0
def test_general_import_era_insert(sess):
    site = Site.insert(sess, "CI017", "Water Works")
    market_role_Z = MarketRole.insert(sess, "Z", "Non-core")
    participant = Participant.insert(sess, "CALB", "AK Industries")
    participant.insert_party(sess, market_role_Z, "None core",
                             utc_datetime(2000, 1, 1), None, None)
    bank_holiday_rate_script = {"bank_holidays": []}
    Contract.insert_non_core(
        sess,
        "bank_holidays",
        "",
        {},
        utc_datetime(2000, 1, 1),
        None,
        bank_holiday_rate_script,
    )
    market_role_X = MarketRole.insert(sess, "X", "Supplier")
    market_role_M = MarketRole.insert(sess, "M", "Mop")
    market_role_C = MarketRole.insert(sess, "C", "HH Dc")
    market_role_R = MarketRole.insert(sess, "R", "Distributor")
    participant.insert_party(sess, market_role_M, "Fusion Mop Ltd",
                             utc_datetime(2000, 1, 1), None, None)
    participant.insert_party(sess, market_role_X, "Fusion Ltc",
                             utc_datetime(2000, 1, 1), None, None)
    participant.insert_party(sess, market_role_C, "Fusion DC",
                             utc_datetime(2000, 1, 1), None, None)
    mop_contract = Contract.insert_mop(sess, "Fusion", participant, "", {},
                                       utc_datetime(2000, 1, 1), None, {})
    dc_contract = Contract.insert_dc(sess, "Fusion DC 2000", participant, "",
                                     {}, utc_datetime(2000, 1, 1), None, {})
    pc = Pc.insert(sess, "00", "hh", utc_datetime(2000, 1, 1), None)
    insert_cops(sess)
    cop = Cop.get_by_code(sess, "5")
    insert_comms(sess)
    comm = Comm.get_by_code(sess, "GSM")
    exp_supplier_contract = Contract.insert_supplier(
        sess,
        "Fusion Supplier 2000",
        participant,
        "",
        {},
        utc_datetime(2000, 1, 1),
        None,
        {},
    )
    dno = participant.insert_party(sess, market_role_R, "WPD",
                                   utc_datetime(2000, 1, 1), None, "22")
    meter_type = MeterType.insert(sess, "C5", "COP 1-5",
                                  utc_datetime(2000, 1, 1), None)
    meter_payment_type = MeterPaymentType.insert(sess, "CR", "Credit",
                                                 utc_datetime(1996, 1, 1),
                                                 None)
    Mtc.insert(
        sess,
        None,
        "845",
        "HH COP5 And Above With Comms",
        False,
        False,
        True,
        meter_type,
        meter_payment_type,
        0,
        utc_datetime(1996, 1, 1),
        None,
    )
    insert_voltage_levels(sess)
    voltage_level = VoltageLevel.get_by_code(sess, "HV")
    dno.insert_llfc(
        sess,
        "510",
        "PC 5-8 & HH HV",
        voltage_level,
        False,
        True,
        utc_datetime(1996, 1, 1),
        None,
    )
    dno.insert_llfc(
        sess,
        "521",
        "Export (HV)",
        voltage_level,
        False,
        False,
        utc_datetime(1996, 1, 1),
        None,
    )
    insert_sources(sess)
    source = Source.get_by_code(sess, "net")
    insert_energisation_statuses(sess)
    energisation_status = EnergisationStatus.get_by_code(sess, "E")
    gsp_group = GspGroup.insert(sess, "_L", "South Western")
    site.insert_e_supply(
        sess,
        source,
        None,
        "Bob",
        utc_datetime(2000, 1, 1),
        None,
        gsp_group,
        mop_contract,
        "773",
        dc_contract,
        "ghyy3",
        "hgjeyhuw",
        pc,
        "845",
        cop,
        comm,
        None,
        energisation_status,
        {},
        None,
        None,
        None,
        None,
        None,
        "22 7867 6232 781",
        "521",
        exp_supplier_contract,
        "7748",
        361,
    )

    sess.commit()

    action = "insert"
    vals = [
        "22 7867 6232 781",
        "2020-10-01 00:00",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
        "Fusion Supplier 2000",
        "{no change}",
        "{no change}",
        "{no change}",
        "{no change}",
    ]
    args = []
    chellow.general_import.general_import_era(sess, action, vals, args)
Пример #10
0
def content(scenario_props, base_name, site_id, supply_id, user, compression,
            site_codes, now):
    report_context = {}

    try:
        comp = report_context["computer"]
    except KeyError:
        comp = report_context["computer"] = {}

    try:
        rate_cache = comp["rates"]
    except KeyError:
        rate_cache = comp["rates"] = {}

    try:
        ind_cont = report_context["contract_names"]
    except KeyError:
        ind_cont = report_context["contract_names"] = {}

    sess = None
    try:
        sess = Session()

        start_year = scenario_props["scenario_start_year"]
        start_month = scenario_props["scenario_start_month"]
        months = scenario_props["scenario_duration"]

        month_pairs = list(
            c_months_u(start_year=start_year,
                       start_month=start_month,
                       months=months))
        start_date_utc = month_pairs[0][0]
        finish_date_utc = month_pairs[-1][-1]

        base_name.append(
            hh_format(start_date_utc).replace(" ", "_").replace(":",
                                                                "").replace(
                                                                    "-", ""))

        base_name.append("for")
        base_name.append(str(months))
        base_name.append("months")

        if "forecast_from" in scenario_props:
            forecast_from = scenario_props["forecast_from"]
        else:
            forecast_from = None

        if forecast_from is None:
            forecast_from = chellow.computer.forecast_date()
        else:
            forecast_from = to_utc(forecast_from)

        sites = sess.query(Site).distinct().order_by(Site.code)
        if site_id is not None:
            site = Site.get_by_id(sess, site_id)
            sites = sites.filter(Site.id == site.id)
            base_name.append("site")
            base_name.append(site.code)
        if supply_id is not None:
            supply = Supply.get_by_id(sess, supply_id)
            base_name.append("supply")
            base_name.append(str(supply.id))
            sites = sites.join(SiteEra).join(Era).filter(Era.supply == supply)
        if len(site_codes) > 0:
            base_name.append("sitecodes")
            sites = sites.filter(Site.code.in_(site_codes))

        running_name, finished_name = chellow.dloads.make_names(
            "_".join(base_name) + ".ods", user)

        rf = open(running_name, "wb")
        site_rows = []
        era_rows = []

        for rate_script in scenario_props.get("local_rates", []):
            contract_id = rate_script["contract_id"]
            try:
                cont_cache = rate_cache[contract_id]
            except KeyError:
                cont_cache = rate_cache[contract_id] = {}

            try:
                rate_script_start = rate_script["start_date"]
            except KeyError:
                raise BadRequest(
                    f"Problem in the scenario properties. Can't find the "
                    f"'start_date' key of the contract {contract_id} in "
                    f"the 'local_rates' map.")

            try:
                rate_script_start = rate_script["start_date"]
            except KeyError:
                raise BadRequest(
                    f"Problem in the scenario properties. Can't find the "
                    f"'start_date' key of the contract {contract_id} in "
                    f"the 'local_rates' map.")

            props = PropDict("scenario properties", rate_script["script"])
            for dt in hh_range(report_context, rate_script_start,
                               rate_script["finish_date"]):
                cont_cache[dt] = props

        for rate_script in scenario_props.get("industry_rates", []):
            contract_name = rate_script["contract_name"]
            try:
                cont_cache = ind_cont[contract_name]
            except KeyError:
                cont_cache = ind_cont[contract_name] = {}

            rfinish = rate_script["finish_date"]
            if rfinish is None:
                raise BadRequest(
                    f"For the industry rate {contract_name} the finish_date "
                    f"can't be null.")
            for dt in hh_range(report_context, rate_script["start_date"],
                               rfinish):
                cont_cache[dt] = PropDict("scenario properties",
                                          rate_script["script"])

        era_maps = scenario_props.get("era_maps", {})
        by_hh = scenario_props.get("by_hh", False)

        scenario_hh = scenario_props.get("hh_data", {})

        era_header_titles = [
            "creation-date",
            "imp-mpan-core",
            "imp-supplier-contract",
            "exp-mpan-core",
            "exp-supplier-contract",
            "metering-type",
            "source",
            "generator-type",
            "supply-name",
            "msn",
            "pc",
            "site-id",
            "site-name",
            "associated-site-ids",
            "month",
        ]
        site_header_titles = [
            "creation-date",
            "site-id",
            "site-name",
            "associated-site-ids",
            "month",
            "metering-type",
            "sources",
            "generator-types",
        ]
        summary_titles = [
            "import-net-kwh",
            "export-net-kwh",
            "import-gen-kwh",
            "export-gen-kwh",
            "import-3rd-party-kwh",
            "export-3rd-party-kwh",
            "displaced-kwh",
            "used-kwh",
            "used-3rd-party-kwh",
            "import-net-gbp",
            "export-net-gbp",
            "import-gen-gbp",
            "export-gen-gbp",
            "import-3rd-party-gbp",
            "export-3rd-party-gbp",
            "displaced-gbp",
            "used-gbp",
            "used-3rd-party-gbp",
            "billed-import-net-kwh",
            "billed-import-net-gbp",
            "billed-supplier-import-net-gbp",
            "billed-dc-import-net-gbp",
            "billed-mop-import-net-gbp",
        ]

        title_dict = {}
        for cont_type, con_attr in (
            ("mop", Era.mop_contract),
            ("dc", Era.dc_contract),
            ("imp-supplier", Era.imp_supplier_contract),
            ("exp-supplier", Era.exp_supplier_contract),
        ):
            titles = []
            title_dict[cont_type] = titles
            conts = (sess.query(Contract).join(con_attr).join(
                Era.supply).join(Source).filter(
                    Era.start_date <= finish_date_utc,
                    or_(Era.finish_date == null(),
                        Era.finish_date >= start_date_utc),
                ).distinct().order_by(Contract.id))
            if supply_id is not None:
                conts = conts.filter(Era.supply_id == supply_id)
            for cont in conts:
                title_func = chellow.computer.contract_func(
                    report_context, cont, "virtual_bill_titles")
                if title_func is None:
                    raise Exception(
                        f"For the contract {cont.name} there doesn't seem to "
                        f"be a 'virtual_bill_titles' function.")
                for title in title_func():
                    if title not in titles:
                        titles.append(title)

        tpr_query = (sess.query(Tpr).join(MeasurementRequirement).join(
            Ssc).join(Era).filter(
                Era.start_date <= finish_date_utc,
                or_(Era.finish_date == null(),
                    Era.finish_date >= start_date_utc),
            ).order_by(Tpr.code).distinct())
        for tpr in tpr_query.filter(Era.imp_supplier_contract != null()):
            for suffix in ("-kwh", "-rate", "-gbp"):
                title_dict["imp-supplier"].append(tpr.code + suffix)
        for tpr in tpr_query.filter(Era.exp_supplier_contract != null()):
            for suffix in ("-kwh", "-rate", "-gbp"):
                title_dict["exp-supplier"].append(tpr.code + suffix)

        era_rows.append(
            era_header_titles + summary_titles + [None] +
            ["mop-" + t for t in title_dict["mop"]] + [None] +
            ["dc-" + t for t in title_dict["dc"]] + [None] +
            ["imp-supplier-" + t for t in title_dict["imp-supplier"]] +
            [None] + ["exp-supplier-" + t for t in title_dict["exp-supplier"]])
        site_rows.append(site_header_titles + summary_titles)

        sites = sites.all()
        deltas = {}
        normal_reads = set()
        normal_read_rows = []

        for site in sites:
            deltas[site.id] = _make_site_deltas(sess, report_context, site,
                                                scenario_hh, forecast_from,
                                                supply_id)

        for month_start, month_finish in month_pairs:
            for site in sites:
                if by_hh:
                    sf = [(d, d) for d in hh_range(report_context, month_start,
                                                   month_finish)]
                else:
                    sf = [(month_start, month_finish)]

                for start, finish in sf:
                    normal_reads = normal_reads | _process_site(
                        sess,
                        report_context,
                        forecast_from,
                        start,
                        finish,
                        site,
                        deltas[site.id],
                        supply_id,
                        era_maps,
                        now,
                        summary_titles,
                        title_dict,
                        era_rows,
                        site_rows,
                    )

            normal_read_rows = [[
                "mpan_core", "date", "msn", "type", "registers"
            ]]
            for mpan_core, r in sorted(list(normal_reads)):
                row = [mpan_core, r.date, r.msn, r.type] + list(r.reads)
                normal_read_rows.append(row)

            write_spreadsheet(rf, compression, site_rows, era_rows,
                              normal_read_rows)
    except BadRequest as e:
        msg = e.description + traceback.format_exc()
        sys.stderr.write(msg + "\n")
        site_rows.append(["Problem " + msg])
        write_spreadsheet(rf, compression, site_rows, era_rows,
                          normal_read_rows)
    except BaseException:
        msg = traceback.format_exc()
        sys.stderr.write(msg + "\n")
        site_rows.append(["Problem " + msg])
        write_spreadsheet(rf, compression, site_rows, era_rows,
                          normal_read_rows)
    finally:
        if sess is not None:
            sess.close()
        try:
            rf.close()
            os.rename(running_name, finished_name)
        except BaseException:
            msg = traceback.format_exc()
            r_name, f_name = chellow.dloads.make_names("error.txt", user)
            ef = open(r_name, "w")
            ef.write(msg + "\n")
            ef.close()
Пример #11
0
def test_scenario_new_generation(mocker, sess):
    site = Site.insert(sess, "CI017", "Water Works")
    start_date = utc_datetime(2009, 7, 31, 23, 00)
    finish_date = utc_datetime(2009, 8, 31, 22, 30)
    supply_id = None
    report_context = {}
    forecast_from = utc_datetime(2020, 1, 1)

    market_role_Z = MarketRole.insert(sess, "Z", "Non-core")
    participant = Participant.insert(sess, "CALB", "AK Industries")
    participant.insert_party(sess, market_role_Z, "None core",
                             utc_datetime(2000, 1, 1), None, None)
    bank_holiday_rate_script = {"bank_holidays": []}
    Contract.insert_non_core(
        sess,
        "bank_holidays",
        "",
        {},
        utc_datetime(2000, 1, 1),
        None,
        bank_holiday_rate_script,
    )
    market_role_X = MarketRole.insert(sess, "X", "Supplier")
    market_role_M = MarketRole.insert(sess, "M", "Mop")
    market_role_C = MarketRole.insert(sess, "C", "HH Dc")
    market_role_R = MarketRole.insert(sess, "R", "Distributor")
    participant.insert_party(sess, market_role_M, "Fusion Mop Ltd",
                             utc_datetime(2000, 1, 1), None, None)
    participant.insert_party(sess, market_role_X, "Fusion Ltc",
                             utc_datetime(2000, 1, 1), None, None)
    participant.insert_party(sess, market_role_C, "Fusion DC",
                             utc_datetime(2000, 1, 1), None, None)
    mop_contract = Contract.insert_mop(sess, "Fusion", participant, "", {},
                                       utc_datetime(2000, 1, 1), None, {})
    dc_contract = Contract.insert_dc(sess, "Fusion DC 2000", participant, "",
                                     {}, utc_datetime(2000, 1, 1), None, {})
    pc = Pc.insert(sess, "00", "hh", utc_datetime(2000, 1, 1), None)
    insert_cops(sess)
    cop = Cop.get_by_code(sess, "5")
    insert_comms(sess)
    comm = Comm.get_by_code(sess, "GSM")
    imp_supplier_contract = Contract.insert_supplier(
        sess,
        "Fusion Supplier 2000",
        participant,
        "",
        {},
        utc_datetime(2000, 1, 1),
        None,
        {},
    )
    dno = participant.insert_party(sess, market_role_R, "WPD",
                                   utc_datetime(2000, 1, 1), None, "22")
    meter_type = MeterType.insert(sess, "C5", "COP 1-5",
                                  utc_datetime(2000, 1, 1), None)
    meter_payment_type = MeterPaymentType.insert(sess, "CR", "Credit",
                                                 utc_datetime(1996, 1, 1),
                                                 None)
    Mtc.insert(
        sess,
        None,
        "845",
        "HH COP5 And Above With Comms",
        False,
        False,
        True,
        meter_type,
        meter_payment_type,
        0,
        utc_datetime(1996, 1, 1),
        None,
    )
    insert_voltage_levels(sess)
    voltage_level = VoltageLevel.get_by_code(sess, "HV")
    dno.insert_llfc(
        sess,
        "510",
        "PC 5-8 & HH HV",
        voltage_level,
        False,
        True,
        utc_datetime(1996, 1, 1),
        None,
    )
    dno.insert_llfc(
        sess,
        "521",
        "Export (HV)",
        voltage_level,
        False,
        False,
        utc_datetime(1996, 1, 1),
        None,
    )
    insert_sources(sess)
    source = Source.get_by_code(sess, "net")
    insert_energisation_statuses(sess)
    energisation_status = EnergisationStatus.get_by_code(sess, "E")
    gsp_group = GspGroup.insert(sess, "_L", "South Western")
    site.insert_e_supply(
        sess,
        source,
        None,
        "Bob",
        utc_datetime(2000, 1, 1),
        None,
        gsp_group,
        mop_contract,
        "773",
        dc_contract,
        "ghyy3",
        "hgjeyhuw",
        pc,
        "845",
        cop,
        comm,
        None,
        energisation_status,
        {},
        "22 7867 6232 781",
        "510",
        imp_supplier_contract,
        "7748",
        361,
        None,
        None,
        None,
        None,
        None,
    )

    sess.commit()

    scenario_hh = {
        "CI017": {
            "generated":
            """
                2009-08-01 00:00, 40
                2009-08-15 00:00, 40"""
        }
    }

    era_maps = {
        utc_datetime(2000, 8, 1): {
            "llfcs": {
                "22": {
                    "new_export": "521"
                }
            },
            "supplier_contracts": {
                "new_export": 4
            },
        }
    }

    site_deltas = _make_site_deltas(sess, report_context, site, scenario_hh,
                                    forecast_from, supply_id)
    calcs, _, _ = _make_calcs(
        sess,
        site,
        start_date,
        finish_date,
        supply_id,
        site_deltas,
        forecast_from,
        report_context,
        era_maps,
    )

    assert calcs[1][1] == "CI017_extra_gen_TRUE"
    assert calcs[2][2] == "CI017_extra_net_export"
Пример #12
0
def test_init_hh_data(sess, mocker):
    """New style channels"""
    site = Site.insert(sess, "CI017", "Water Works")
    market_role_Z = MarketRole.insert(sess, "Z", "Non-core")
    participant = Participant.insert(sess, "CALB", "AK Industries")
    participant.insert_party(sess, market_role_Z, "None core",
                             utc_datetime(2000, 1, 1), None, None)
    bank_holiday_rate_script = {"bank_holidays": []}
    Contract.insert_non_core(
        sess,
        "bank_holidays",
        "",
        {},
        utc_datetime(2000, 1, 1),
        None,
        bank_holiday_rate_script,
    )
    market_role_X = MarketRole.insert(sess, "X", "Supplier")
    market_role_M = MarketRole.insert(sess, "M", "Mop")
    market_role_C = MarketRole.insert(sess, "C", "HH Dc")
    market_role_R = MarketRole.insert(sess, "R", "Distributor")
    participant.insert_party(sess, market_role_M, "Fusion Mop Ltd",
                             utc_datetime(2000, 1, 1), None, None)
    participant.insert_party(sess, market_role_X, "Fusion Ltc",
                             utc_datetime(2000, 1, 1), None, None)
    participant.insert_party(sess, market_role_C, "Fusion DC",
                             utc_datetime(2000, 1, 1), None, None)
    mop_contract = Contract.insert_mop(sess, "Fusion", participant, "", {},
                                       utc_datetime(2000, 1, 1), None, {})
    dc_contract = Contract.insert_hhdc(sess, "Fusion DC 2000", participant, "",
                                       {}, utc_datetime(2000, 1, 1), None, {})
    pc = Pc.insert(sess, "00", "hh", utc_datetime(2000, 1, 1), None)
    insert_cops(sess)
    cop = Cop.get_by_code(sess, "5")
    imp_supplier_contract = Contract.insert_supplier(
        sess,
        "Fusion Supplier 2000",
        participant,
        "",
        {},
        utc_datetime(2000, 1, 1),
        None,
        {},
    )
    dno = participant.insert_party(sess, market_role_R, "WPD",
                                   utc_datetime(2000, 1, 1), None, "22")
    meter_type = MeterType.insert(sess, "C5", "COP 1-5",
                                  utc_datetime(2000, 1, 1), None)
    meter_payment_type = MeterPaymentType.insert(sess, "CR", "Credit",
                                                 utc_datetime(1996, 1, 1),
                                                 None)
    Mtc.insert(
        sess,
        None,
        "845",
        "HH COP5 And Above With Comms",
        False,
        False,
        True,
        meter_type,
        meter_payment_type,
        0,
        utc_datetime(1996, 1, 1),
        None,
    )
    insert_voltage_levels(sess)
    voltage_level = VoltageLevel.get_by_code(sess, "HV")
    dno.insert_llfc(
        sess,
        "510",
        "PC 5-8 & HH HV",
        voltage_level,
        False,
        True,
        utc_datetime(1996, 1, 1),
        None,
    )
    dno.insert_llfc(
        sess,
        "521",
        "Export (HV)",
        voltage_level,
        False,
        False,
        utc_datetime(1996, 1, 1),
        None,
    )
    insert_sources(sess)
    source = Source.get_by_code(sess, "net")
    insert_energisation_statuses(sess)
    energisation_status = EnergisationStatus.get_by_code(sess, "E")
    gsp_group = GspGroup.insert(sess, "_L", "South Western")
    supply = site.insert_e_supply(
        sess,
        source,
        None,
        "Bob",
        utc_datetime(2000, 1, 1),
        None,
        gsp_group,
        mop_contract,
        "773",
        dc_contract,
        "ghyy3",
        "hgjeyhuw",
        pc,
        "845",
        cop,
        None,
        energisation_status,
        {},
        "22 7867 6232 781",
        "510",
        imp_supplier_contract,
        "7748",
        361,
        None,
        None,
        None,
        None,
        None,
    )
    era = supply.eras[0]
    channel = era.insert_channel(sess, True, "ACTIVE")
    data_raw = [{
        "start_date": utc_datetime(2009, 8, 10),
        "value": 10,
        "status": "A",
    }]
    channel.add_hh_data(sess, data_raw)

    sess.commit()

    caches = {}
    chunk_start = utc_datetime(2009, 7, 31, 23, 00)
    chunk_finish = utc_datetime(2009, 8, 31, 22, 30)
    is_import = True
    full_channels, hhd = chellow.computer._init_hh_data(
        sess, caches, era, chunk_start, chunk_finish, is_import)

    assert full_channels

    expected_hhd = {
        utc_datetime(2009, 8, 10): {
            "imp-msp-kvarh": 0.0,
            "imp-msp-kvar": 0.0,
            "exp-msp-kvarh": 0.0,
            "exp-msp-kvar": 0.0,
            "status": "A",
            "hist-kwh": 10.0,
            "msp-kwh": 10.0,
            "msp-kw": 20.0,
        }
    }
    assert hhd == expected_hhd
Пример #13
0
def test_bill_after_end_supply(mocker, sess):
    site = Site.insert(sess, "CI017", "Water Works")
    start_date = utc_datetime(2009, 7, 31, 23, 00)
    months = 1
    supply_id = None

    market_role_Z = MarketRole.insert(sess, "Z", "Non-core")
    participant = Participant.insert(sess, "CALB", "AK Industries")
    participant.insert_party(sess, market_role_Z, "None core",
                             utc_datetime(2000, 1, 1), None, None)
    bank_holiday_rate_script = {"bank_holidays": []}
    Contract.insert_non_core(
        sess,
        "bank_holidays",
        "",
        {},
        utc_datetime(2000, 1, 1),
        None,
        bank_holiday_rate_script,
    )
    market_role_X = MarketRole.insert(sess, "X", "Supplier")
    market_role_M = MarketRole.insert(sess, "M", "Mop")
    market_role_C = MarketRole.insert(sess, "C", "HH Dc")
    market_role_R = MarketRole.insert(sess, "R", "Distributor")
    participant.insert_party(sess, market_role_M, "Fusion Mop Ltd",
                             utc_datetime(2000, 1, 1), None, None)
    participant.insert_party(sess, market_role_X, "Fusion Ltc",
                             utc_datetime(2000, 1, 1), None, None)
    participant.insert_party(sess, market_role_C, "Fusion DC",
                             utc_datetime(2000, 1, 1), None, None)

    mop_charge_script = """
from chellow.utils import reduce_bill_hhs

def virtual_bill_titles():
    return ['net-gbp', 'problem']

def virtual_bill(ds):
    for hh in ds.hh_data:
        hh_start = hh['start-date']
        bill_hh = ds.supplier_bill_hhs[hh_start]

        bill_hh['net-gbp'] = sum(
            v for k, v in bill_hh.items() if k.endswith('gbp'))

    ds.mop_bill = reduce_bill_hhs(ds.supplier_bill_hhs)
"""
    mop_contract = Contract.insert_mop(
        sess,
        "Fusion Mop Contract",
        participant,
        mop_charge_script,
        {},
        utc_datetime(2000, 1, 1),
        None,
        {},
    )

    dc_charge_script = """
from chellow.utils import reduce_bill_hhs

def virtual_bill_titles():
    return ['net-gbp', 'problem']

def virtual_bill(ds):
    for hh in ds.hh_data:
        hh_start = hh['start-date']
        bill_hh = ds.supplier_bill_hhs[hh_start]

        bill_hh['net-gbp'] = sum(
            v for k, v in bill_hh.items() if k.endswith('gbp'))

    ds.dc_bill = reduce_bill_hhs(ds.supplier_bill_hhs)
"""

    dc_contract = Contract.insert_dc(
        sess,
        "Fusion DC 2000",
        participant,
        dc_charge_script,
        {},
        utc_datetime(2000, 1, 1),
        None,
        {},
    )
    pc = Pc.insert(sess, "00", "hh", utc_datetime(2000, 1, 1), None)
    insert_cops(sess)
    cop = Cop.get_by_code(sess, "5")
    insert_comms(sess)
    comm = Comm.get_by_code(sess, "GSM")

    supplier_charge_script = """
import chellow.ccl
from chellow.utils import HH, reduce_bill_hhs, utc_datetime

def virtual_bill_titles():
    return [
        'ccl-kwh', 'ccl-rate', 'ccl-gbp', 'net-gbp', 'vat-gbp', 'gross-gbp',
        'sum-msp-kwh', 'sum-msp-gbp', 'problem']

def virtual_bill(ds):
    for hh in ds.hh_data:
        hh_start = hh['start-date']
        bill_hh = ds.supplier_bill_hhs[hh_start]
        bill_hh['sum-msp-kwh'] = hh['msp-kwh']
        bill_hh['sum-msp-gbp'] = hh['msp-kwh'] * 0.1
        bill_hh['net-gbp'] = sum(
            v for k, v in bill_hh.items() if k.endswith('gbp'))
        bill_hh['vat-gbp'] = 0
        bill_hh['gross-gbp'] = bill_hh['net-gbp'] + bill_hh['vat-gbp']

    ds.supplier_bill = reduce_bill_hhs(ds.supplier_bill_hhs)
"""
    imp_supplier_contract = Contract.insert_supplier(
        sess,
        "Fusion Supplier 2000",
        participant,
        supplier_charge_script,
        {},
        utc_datetime(2000, 1, 1),
        None,
        {},
    )
    batch = imp_supplier_contract.insert_batch(sess, "a b", "")
    dno = participant.insert_party(sess, market_role_R, "WPD",
                                   utc_datetime(2000, 1, 1), None, "22")
    meter_type = MeterType.insert(sess, "C5", "COP 1-5",
                                  utc_datetime(2000, 1, 1), None)
    meter_payment_type = MeterPaymentType.insert(sess, "CR", "Credit",
                                                 utc_datetime(1996, 1, 1),
                                                 None)
    Mtc.insert(
        sess,
        None,
        "845",
        "HH COP5 And Above With Comms",
        False,
        False,
        True,
        meter_type,
        meter_payment_type,
        0,
        utc_datetime(1996, 1, 1),
        None,
    )
    insert_voltage_levels(sess)
    voltage_level = VoltageLevel.get_by_code(sess, "HV")
    dno.insert_llfc(
        sess,
        "510",
        "PC 5-8 & HH HV",
        voltage_level,
        False,
        True,
        utc_datetime(1996, 1, 1),
        None,
    )
    dno.insert_llfc(
        sess,
        "521",
        "Export (HV)",
        voltage_level,
        False,
        False,
        utc_datetime(1996, 1, 1),
        None,
    )
    insert_sources(sess)
    source = Source.get_by_code(sess, "net")
    gsp_group = GspGroup.insert(sess, "_L", "South Western")
    insert_energisation_statuses(sess)
    energisation_status = EnergisationStatus.get_by_code(sess, "E")
    supply = site.insert_e_supply(
        sess,
        source,
        None,
        "Bob",
        utc_datetime(2000, 1, 1),
        utc_datetime(2000, 1, 31, 23, 30),
        gsp_group,
        mop_contract,
        "773",
        dc_contract,
        "ghyy3",
        "hgjeyhuw",
        pc,
        "845",
        cop,
        comm,
        None,
        energisation_status,
        {},
        "22 7867 6232 781",
        "510",
        imp_supplier_contract,
        "7748",
        361,
        None,
        None,
        None,
        None,
        None,
    )
    insert_bill_types(sess)
    bill_type = sess.execute(
        select(BillType).where(BillType.code == "N")).scalar_one()
    batch.insert_bill(
        sess,
        "dd",
        "hjk",
        start_date,
        utc_datetime(2009, 7, 10),
        utc_datetime(2009, 7, 10),
        Decimal("10.00"),
        Decimal("10.00"),
        Decimal("10.00"),
        Decimal("10.00"),
        bill_type,
        {},
        supply,
    )

    sess.commit()

    scenario_props = {
        "scenario_start_year": start_date.year,
        "scenario_start_month": start_date.month,
        "scenario_duration": months,
        "by_hh": False,
    }
    base_name = ["monthly_duration"]
    site_id = site.id
    user = mocker.Mock()
    compression = False
    site_codes = []
    now = utc_datetime(2020, 1, 1)

    mock_file = BytesIO()
    mock_file.close = mocker.Mock()
    mocker.patch("chellow.reports.report_247.open", return_value=mock_file)
    mocker.patch("chellow.reports.report_247.chellow.dloads.make_names",
                 return_value=("a", "b"))
    mocker.patch("chellow.reports.report_247.os.rename")

    content(
        scenario_props,
        base_name,
        site_id,
        supply_id,
        user,
        compression,
        site_codes,
        now,
    )

    sheet = odio.parse_spreadsheet(mock_file)
    table = list(sheet.tables[0].rows)

    expected = [
        [
            "creation-date",
            "site-id",
            "site-name",
            "associated-site-ids",
            "month",
            "metering-type",
            "sources",
            "generator-types",
            "import-net-kwh",
            "export-net-kwh",
            "import-gen-kwh",
            "export-gen-kwh",
            "import-3rd-party-kwh",
            "export-3rd-party-kwh",
            "displaced-kwh",
            "used-kwh",
            "used-3rd-party-kwh",
            "import-net-gbp",
            "export-net-gbp",
            "import-gen-gbp",
            "export-gen-gbp",
            "import-3rd-party-gbp",
            "export-3rd-party-gbp",
            "displaced-gbp",
            "used-gbp",
            "used-3rd-party-gbp",
            "billed-import-net-kwh",
            "billed-import-net-gbp",
            "billed-supplier-import-net-gbp",
            "billed-dc-import-net-gbp",
            "billed-mop-import-net-gbp",
        ],
        [
            Datetime(2020, 1, 1, 0, 0),
            "CI017",
            "Water Works",
            "",
            Datetime(2009, 7, 31, 23, 30),
            None,
            "",
            "",
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            0.0,
            10.0,
            10.0,
            0.0,
            0.0,
        ],
    ]

    assert expected == table
Пример #14
0
def test_bill_http(mocker, sess, client):
    site = Site.insert(sess, "22488", "Water Works")
    g_dn = GDn.insert(sess, "EE", "East of England")
    g_ldz = g_dn.insert_g_ldz(sess, "EA")
    g_exit_zone = g_ldz.insert_g_exit_zone(sess, "EA1")
    insert_g_units(sess)
    g_unit_M3 = GUnit.get_by_code(sess, "M3")
    participant = Participant.insert(sess, "CALB", "AK Industries")
    market_role_Z = MarketRole.get_by_code(sess, "Z")
    participant.insert_party(sess, market_role_Z, "None core",
                             utc_datetime(2000, 1, 1), None, None)
    g_contract = GContract.insert(sess, "Fusion 2020", "", {},
                                  utc_datetime(2000, 1, 1), None, {})
    insert_g_reading_frequencies(sess)
    g_reading_frequency_M = GReadingFrequency.get_by_code(sess, "M")
    g_supply = site.insert_g_supply(
        sess,
        "87614362",
        "main",
        g_exit_zone,
        utc_datetime(2018, 1, 1),
        None,
        "hgeu8rhg",
        1,
        g_unit_M3,
        g_contract,
        "d7gthekrg",
        g_reading_frequency_M,
    )
    g_batch = g_contract.insert_g_batch(sess, "b1", "Jan batch")

    breakdown = {"units_consumed": 771}
    insert_bill_types(sess)
    bill_type_n = BillType.get_by_code(sess, "N")
    g_bill = g_batch.insert_g_bill(
        sess,
        g_supply,
        bill_type_n,
        "55h883",
        "dhgh883",
        utc_datetime(2019, 4, 3),
        utc_datetime(2020, 1, 1),
        utc_datetime(2020, 1, 31, 23, 30),
        Decimal("45"),
        Decimal("12.40"),
        Decimal("1.20"),
        Decimal("14.52"),
        "",
        breakdown,
    )
    sess.commit()

    data = {"g_bill_id": g_bill.id}

    mock_Thread = mocker.patch("chellow.reports.report_429.threading.Thread",
                               autospec=True)
    response = client.get("/reports/429", data=data)

    match(response, 303)

    user = None
    args = (None, g_bill.id, user)
    mock_Thread.assert_called_with(target=chellow.reports.report_429.content,
                                   args=args)
Пример #15
0
def test_Supply_insert_era_at(sess):
    """Where an era is inserted in the last HH of another era, check
    the template era is the one at the insertion date.
    """
    site = Site.insert(sess, "CI017", "Water Works")
    market_role_Z = MarketRole.insert(sess, "Z", "Non-core")
    participant = Participant.insert(sess, "CALB", "AK Industries")
    participant.insert_party(sess, market_role_Z, "None core",
                             utc_datetime(2000, 1, 1), None, None)
    market_role_X = MarketRole.insert(sess, "X", "Supplier")
    market_role_M = MarketRole.insert(sess, "M", "Mop")
    market_role_C = MarketRole.insert(sess, "C", "HH Dc")
    market_role_R = MarketRole.insert(sess, "R", "Distributor")
    participant.insert_party(sess, market_role_M, "Fusion Mop Ltd",
                             utc_datetime(2000, 1, 1), None, None)
    participant.insert_party(sess, market_role_X, "Fusion Ltc",
                             utc_datetime(2000, 1, 1), None, None)
    participant.insert_party(sess, market_role_C, "Fusion DC",
                             utc_datetime(2000, 1, 1), None, None)
    mop_contract = Contract.insert_mop(sess, "Fusion", participant, "", {},
                                       utc_datetime(2000, 1, 1), None, {})
    dc_contract = Contract.insert_hhdc(sess, "Fusion DC 2000", participant, "",
                                       {}, utc_datetime(2000, 1, 1), None, {})
    pc = Pc.insert(sess, "00", "hh", utc_datetime(2000, 1, 1), None)
    insert_cops(sess)
    cop = Cop.get_by_code(sess, "5")
    imp_supplier_contract = Contract.insert_supplier(
        sess,
        "Fusion Supplier 2000",
        participant,
        "",
        {},
        utc_datetime(2000, 1, 1),
        None,
        {},
    )
    dno = participant.insert_party(sess, market_role_R, "WPD",
                                   utc_datetime(2000, 1, 1), None, "22")
    meter_type = MeterType.insert(sess, "C5", "COP 1-5",
                                  utc_datetime(2000, 1, 1), None)
    meter_payment_type = MeterPaymentType.insert(sess, "CR", "Credit",
                                                 utc_datetime(1996, 1, 1),
                                                 None)
    mtc_845 = Mtc.insert(
        sess,
        None,
        "845",
        "HH COP5 And Above With Comms",
        False,
        False,
        True,
        meter_type,
        meter_payment_type,
        0,
        utc_datetime(1996, 1, 1),
        None,
    )
    insert_voltage_levels(sess)
    voltage_level = VoltageLevel.get_by_code(sess, "HV")
    dno.insert_llfc(
        sess,
        "510",
        "PC 5-8 & HH HV",
        voltage_level,
        False,
        True,
        utc_datetime(1996, 1, 1),
        None,
    )
    dno.insert_llfc(
        sess,
        "521",
        "Export (HV)",
        voltage_level,
        False,
        False,
        utc_datetime(1996, 1, 1),
        None,
    )
    insert_sources(sess)
    source = Source.get_by_code(sess, "net")
    insert_energisation_statuses(sess)
    energisation_status = EnergisationStatus.get_by_code(sess, "E")
    gsp_group = GspGroup.insert(sess, "_L", "South Western")
    era1_msn = "e1msn"
    imp_mpan_core = "22 7867 6232 781"
    supply = site.insert_e_supply(
        sess,
        source,
        None,
        "Bob",
        utc_datetime(2000, 1, 1),
        None,
        gsp_group,
        mop_contract,
        "773",
        dc_contract,
        "ghyy3",
        era1_msn,
        pc,
        "845",
        cop,
        None,
        energisation_status,
        {},
        imp_mpan_core,
        "510",
        imp_supplier_contract,
        "7748",
        361,
        None,
        None,
        None,
        None,
        None,
    )
    era1 = supply.eras[0]
    era2_start_date = utc_datetime(2009, 7, 31, 23, 30)
    era2 = supply.insert_era_at(sess, era2_start_date)
    era2_msn = "e2msn"
    era2.update(
        sess,
        era2_start_date,
        None,
        mop_contract,
        "379540",
        dc_contract,
        "547yt",
        era2_msn,
        pc,
        mtc_845,
        cop,
        None,
        energisation_status,
        {},
        imp_mpan_core,
        "510",
        imp_supplier_contract,
        "9745y6",
        361,
        None,
        None,
        None,
        None,
        None,
    )

    sess.commit()

    start_date = utc_datetime(2009, 7, 31, 23, 00)
    era3 = supply.insert_era_at(sess, start_date)
    assert era3.msn == era1.msn
Пример #16
0
def test_supply(mocker, sess, client):
    site = Site.insert(sess, "22488", "Water Works")
    g_dn = GDn.insert(sess, "EE", "East of England")
    g_ldz = g_dn.insert_g_ldz(sess, "EA")
    g_exit_zone = g_ldz.insert_g_exit_zone(sess, "EA1")
    insert_g_units(sess)
    g_unit_M3 = GUnit.get_by_code(sess, "M3")
    participant = Participant.insert(sess, "CALB", "AK Industries")
    market_role_Z = MarketRole.get_by_code(sess, "Z")
    participant.insert_party(sess, market_role_Z, "None core",
                             utc_datetime(2000, 1, 1), None, None)
    g_cv_rate_script = {
        "cvs": {
            "EA": {
                1: {
                    "applicable_at": utc_datetime(2020, 10, 3),
                    "cv": 39.2000
                },
            }
        }
    }
    Contract.insert_non_core(sess, "g_cv", "", {}, utc_datetime(2000, 1, 1),
                             None, g_cv_rate_script)
    bank_holiday_rate_script = {"bank_holidays": []}
    Contract.insert_non_core(
        sess,
        "bank_holidays",
        "",
        {},
        utc_datetime(2000, 1, 1),
        None,
        bank_holiday_rate_script,
    )
    charge_script = """
import chellow.g_ccl
from chellow.g_engine import g_rates
from chellow.utils import reduce_bill_hhs


def virtual_bill_titles():
    return [
        'units_consumed', 'correction_factor', 'unit_code', 'unit_factor',
        'calorific_value', 'kwh', 'gas_rate', 'gas_gbp', 'ccl_rate',
        'standing_rate', 'standing_gbp', 'net_gbp', 'vat_gbp', 'gross_gbp',
        'problem']


def virtual_bill(ds):
    chellow.g_ccl.vb(ds)
    for hh in ds.hh_data:
        start_date = hh['start_date']
        bill_hh = ds.bill_hhs[start_date]
        bill_hh['units_consumed'] = hh['units_consumed']
        bill_hh['correction_factor'] = {hh['correction_factor']}
        bill_hh['unit_code'] = {hh['unit_code']}
        bill_hh['unit_factor'] = {hh['unit_factor']}
        bill_hh['calorific_value'] = {hh['calorific_value']}
        kwh = hh['kwh']
        bill_hh['kwh'] = kwh
        gas_rate = float(
            g_rates(ds.sess, ds.caches, db_id, start_date)['gas_rate'])
        bill_hh['gas_rate'] = {gas_rate}
        bill_hh['gas_gbp'] = gas_rate * kwh
        bill_hh['ccl_kwh'] = kwh
        ccl_rate = hh['ccl']
        bill_hh['ccl_rate'] = {ccl_rate}
        bill_hh['ccl_kwh'] = kwh
        bill_hh['ccl_gbp'] = kwh * ccl_rate
        if hh['utc_is_month_end']:
            standing_rate = float(
                g_rates(
                    ds.sess, ds.caches, db_id, start_date)['standing_rate'])
            bill_hh['standing_rate'] = {standing_rate}
            bill_hh['standing_gbp'] = standing_rate
        if hh['utc_decimal_hour'] == 0:
            pass

        bill_hh['net_gbp'] = sum(
            v for k, v in bill_hh.items() if k.endswith('gbp'))
        bill_hh['vat_gbp'] = 0
        bill_hh['gross_gbp'] = bill_hh['net_gbp'] + bill_hh['vat_gbp']

    ds.bill = reduce_bill_hhs(ds.bill_hhs)
"""
    g_contract_rate_script = {
        "gas_rate": 0.1,
        "standing_rate": 0.1,
    }
    g_contract = GContract.insert(
        sess,
        "Fusion 2020",
        charge_script,
        {},
        utc_datetime(2000, 1, 1),
        None,
        g_contract_rate_script,
    )
    insert_g_reading_frequencies(sess)
    g_reading_frequency_M = GReadingFrequency.get_by_code(sess, "M")
    msn = "hgeu8rhg"
    g_supply = site.insert_g_supply(
        sess,
        "87614362",
        "main",
        g_exit_zone,
        utc_datetime(2010, 1, 1),
        None,
        msn,
        1,
        g_unit_M3,
        g_contract,
        "d7gthekrg",
        g_reading_frequency_M,
    )
    g_batch = g_contract.insert_g_batch(sess, "b1", "Jan batch")

    breakdown = {"units_consumed": 771}
    insert_bill_types(sess)
    bill_type_N = BillType.get_by_code(sess, "N")
    insert_g_read_types(sess)
    g_read_type_A = GReadType.get_by_code(sess, "A")
    g_bill = g_batch.insert_g_bill(
        sess,
        g_supply,
        bill_type_N,
        "55h883",
        "dhgh883",
        utc_datetime(2019, 4, 3),
        utc_datetime(2015, 9, 1),
        utc_datetime(2015, 9, 30, 22, 30),
        Decimal("45"),
        Decimal("12.40"),
        Decimal("1.20"),
        Decimal("14.52"),
        "",
        breakdown,
    )
    g_bill.insert_g_read(
        sess,
        msn,
        g_unit_M3,
        Decimal("1"),
        Decimal("37"),
        Decimal("90"),
        utc_datetime(2015, 9, 1),
        g_read_type_A,
        Decimal("890"),
        utc_datetime(2015, 9, 25),
        g_read_type_A,
    )
    sess.commit()

    mock_file = BytesIO()
    mock_file.close = mocker.Mock()
    mocker.patch("chellow.reports.report_g_monthly_duration.open",
                 return_value=mock_file)
    mocker.patch(
        "chellow.reports.report_g_monthly_duration.chellow.dloads.make_names",
        return_value=("a", "b"),
    )
    mocker.patch("chellow.reports.report_g_monthly_duration.os.rename")

    user = mocker.Mock()
    site_id = site.id
    g_supply_id = g_supply.id
    compression = False
    finish_year = 2015
    finish_month = 9
    months = 1
    now = utc_datetime(2020, 9, 1)

    chellow.reports.report_g_monthly_duration.content(
        site_id,
        g_supply_id,
        user,
        compression,
        finish_year,
        finish_month,
        months,
        now=now,
    )

    sheet = odio.parse_spreadsheet(mock_file)
    table = list(sheet.tables[1].rows)

    expected = [
        [
            "creation_date",
            "mprn",
            "supply_name",
            "exit_zone",
            "msn",
            "unit",
            "contract",
            "site_id",
            "site_name",
            "associated_site_ids",
            "month",
            "kwh",
            "gbp",
            "billed_kwh",
            "billed_gbp",
            "units_consumed",
            "correction_factor",
            "unit_code",
            "unit_factor",
            "calorific_value",
            "kwh",
            "gas_rate",
            "gas_gbp",
            "ccl_rate",
            "standing_rate",
            "standing_gbp",
            "net_gbp",
            "vat_gbp",
            "gross_gbp",
            "problem",
        ],
        [
            Datetime(2020, 9, 1, 1),
            "87614362",
            "main",
            "EA1",
            "hgeu8rhg",
            "M3",
            "Fusion 2020",
            "22488",
            "Water Works",
            "",
            Datetime(2015, 9, 30, 23, 30),
            10888.888888888665,
            1146.1869155555785,
            45.0,
            12.4,
            1000.0000000000156,
            1.0,
            "M3",
            1.0,
            39.2,
            10888.888888888665,
            0.1,
            1088.8888888888619,
            0.00525288,
            0.1,
            0.1,
            1146.1869155555785,
            0.0,
            1146.1869155555785,
            None,
        ],
    ]

    assert expected == table
Пример #17
0
 def get(self, site_id):
     return Site.get_by_id(g.sess, site_id)
Пример #18
0
def content(base_name, site_id, g_supply_id, user, compression, start_date,
            months):
    now = utc_datetime_now()
    report_context = {}
    sess = None

    try:
        sess = Session()
        base_name.append(
            hh_format(start_date).replace(' ',
                                          '_').replace(':',
                                                       '').replace('-', ''))

        base_name.append('for')
        base_name.append(str(months))
        base_name.append('months')
        finish_date = start_date + relativedelta(months=months)

        forecast_from = chellow.computer.forecast_date()

        sites = sess.query(Site).distinct().order_by(Site.code)
        if site_id is not None:
            site = Site.get_by_id(sess, site_id)
            sites = sites.filter(Site.id == site.id)
            base_name.append('site')
            base_name.append(site.code)
        if g_supply_id is not None:
            g_supply = GSupply.get_by_id(sess, g_supply_id)
            base_name.append('g_supply')
            base_name.append(str(g_supply.id))
            sites = sites.join(SiteGEra).join(GEra).filter(
                GEra.g_supply == g_supply)

        running_name, finished_name = chellow.dloads.make_names(
            '_'.join(base_name) + '.ods', user)

        rf = open(running_name, "wb")
        site_rows = []
        g_era_rows = []

        era_header_titles = [
            'creation_date', 'mprn', 'supply_name', 'exit_zone', 'msn', 'unit',
            'contract', 'site_id', 'site_name', 'associated_site_ids', 'month'
        ]
        site_header_titles = [
            'creation_date', 'site_id', 'site_name', 'associated_site_ids',
            'month'
        ]
        summary_titles = ['kwh', 'gbp', 'billed_kwh', 'billed_gbp']

        vb_titles = []
        conts = sess.query(GContract).join(GEra).join(GSupply).filter(
            GEra.start_date <= finish_date,
            or_(GEra.finish_date == null(),
                GEra.finish_date >= start_date)).distinct().order_by(
                    GContract.id)
        if g_supply_id is not None:
            conts = conts.filter(GEra.g_supply_id == g_supply_id)
        for cont in conts:
            title_func = chellow.computer.contract_func(
                report_context, cont, 'virtual_bill_titles')
            if title_func is None:
                raise Exception("For the contract " + cont.name +
                                " there doesn't seem " +
                                "to be a 'virtual_bill_titles' function.")
            for title in title_func():
                if title not in vb_titles:
                    vb_titles.append(title)

        g_era_rows.append(era_header_titles + summary_titles + vb_titles)
        site_rows.append(site_header_titles + summary_titles)

        sites = sites.all()
        month_start = start_date
        while month_start < finish_date:
            month_finish = month_start + relativedelta(months=1) - HH
            for site in sites:
                site_kwh = site_gbp = site_billed_kwh = site_billed_gbp = 0
                for g_era in sess.query(GEra).join(SiteGEra).filter(
                        SiteGEra.site == site, SiteGEra.is_physical == true(),
                        GEra.start_date <= month_finish,
                        or_(GEra.finish_date == null(),
                            GEra.finish_date >= month_start)).options(
                                joinedload(GEra.g_contract),
                                joinedload(GEra.g_supply),
                                joinedload(GEra.g_supply).joinedload(
                                    GSupply.g_exit_zone)).order_by(GEra.id):

                    g_supply = g_era.g_supply

                    if g_supply_id is not None and g_supply.id != g_supply_id:
                        continue

                    ss_start = hh_max(g_era.start_date, month_start)
                    ss_finish = hh_min(g_era.finish_date, month_finish)

                    ss = GDataSource(sess, ss_start, ss_finish, forecast_from,
                                     g_era, report_context, None)

                    contract = g_era.g_contract
                    vb_function = contract_func(report_context, contract,
                                                'virtual_bill')
                    if vb_function is None:
                        raise BadRequest(
                            "The contract " + contract.name +
                            " doesn't have the virtual_bill() function.")
                    vb_function(ss)
                    bill = ss.bill

                    try:
                        gbp = bill['net_gbp']
                    except KeyError:
                        gbp = 0
                        bill['problem'] += 'For the supply ' + ss.mprn + \
                            ' the virtual bill ' + str(bill) + \
                            ' from the contract ' + contract.name + \
                            ' does not contain the net_gbp key.'
                    try:
                        kwh = bill['kwh']
                    except KeyError:
                        kwh = 0
                        bill['problem'] += "For the supply " + ss.mprn + \
                            " the virtual bill " + str(bill) + \
                            " from the contract " + contract.name + \
                            " does not contain the 'kwh' key."

                    billed_kwh = billed_gbp = 0

                    g_era_associates = {
                        s.site.code
                        for s in g_era.site_g_eras if not s.is_physical
                    }

                    for g_bill in sess.query(GBill).filter(
                            GBill.g_supply == g_supply,
                            GBill.start_date <= ss_finish,
                            GBill.finish_date >= ss_start):
                        bill_start = g_bill.start_date
                        bill_finish = g_bill.finish_date
                        bill_duration = (
                            bill_finish - bill_start).total_seconds() + \
                            (30 * 60)
                        overlap_duration = (min(bill_finish, ss_finish) - max(
                            bill_start, ss_start)).total_seconds() + (30 * 60)
                        overlap_proportion = overlap_duration / bill_duration
                        billed_kwh += overlap_proportion * float(g_bill.kwh)
                        billed_gbp += overlap_proportion * float(g_bill.net)

                    associated_site_ids = ','.join(sorted(g_era_associates))
                    g_era_rows.append([
                        now, g_supply.mprn, g_supply.name, g_supply.g_exit_zone
                        .code, g_era.msn, g_era.g_unit.code, contract.name,
                        site.code, site.name, associated_site_ids,
                        month_finish, kwh, gbp, billed_kwh, billed_gbp
                    ] + [make_val(bill.get(t)) for t in vb_titles])

                    site_kwh += kwh
                    site_gbp += gbp
                    site_billed_kwh += billed_kwh
                    site_billed_gbp += billed_gbp

                linked_sites = ', '.join(s.code
                                         for s in site.find_linked_sites(
                                             sess, month_start, month_finish))

                site_rows.append([
                    now, site.code, site.name, linked_sites, month_finish,
                    site_kwh, site_gbp, site_billed_kwh, site_billed_gbp
                ])
                sess.rollback()
            write_spreadsheet(rf, compression, site_rows, g_era_rows)
            month_start += relativedelta(months=1)
    except BadRequest as e:
        msg = e.description + traceback.format_exc()
        sys.stderr.write(msg + '\n')
        site_rows.append(["Problem " + msg])
        write_spreadsheet(rf, compression, site_rows, g_era_rows)
    except BaseException:
        msg = traceback.format_exc()
        sys.stderr.write(msg + '\n')
        site_rows.append(["Problem " + msg])
        write_spreadsheet(rf, compression, site_rows, g_era_rows)
    finally:
        if sess is not None:
            sess.close()
        try:
            rf.close()
            os.rename(running_name, finished_name)
        except BaseException:
            msg = traceback.format_exc()
            r_name, f_name = chellow.dloads.make_names('error.txt', user)
            ef = open(r_name, "w")
            ef.write(msg + '\n')
            ef.close()
Пример #19
0
def test_process(mocker, sess):
    site = Site.insert(sess, "CI017", "Water Works")

    market_role_Z = MarketRole.insert(sess, "Z", "Non-core")
    participant = Participant.insert(sess, "CALB", "AK Industries")
    participant.insert_party(
        sess, market_role_Z, "None core", utc_datetime(2000, 1, 1), None, None
    )
    bank_holiday_rate_script = {"bank_holidays": []}
    Contract.insert_non_core(
        sess,
        "bank_holidays",
        "",
        {},
        utc_datetime(2000, 1, 1),
        None,
        bank_holiday_rate_script,
    )
    market_role_X = MarketRole.insert(sess, "X", "Supplier")
    market_role_M = MarketRole.insert(sess, "M", "Mop")
    market_role_C = MarketRole.insert(sess, "C", "HH Dc")
    market_role_R = MarketRole.insert(sess, "R", "Distributor")
    participant.insert_party(
        sess, market_role_M, "Fusion Mop Ltd", utc_datetime(2000, 1, 1), None, None
    )
    participant.insert_party(
        sess, market_role_X, "Fusion Ltc", utc_datetime(2000, 1, 1), None, None
    )
    participant.insert_party(
        sess, market_role_C, "Fusion DC", utc_datetime(2000, 1, 1), None, None
    )
    mop_contract = Contract.insert_mop(
        sess, "Fusion", participant, "", {}, utc_datetime(2000, 1, 1), None, {}
    )
    dc_contract = Contract.insert_dc(
        sess, "Fusion DC 2000", participant, "", {}, utc_datetime(2000, 1, 1), None, {}
    )
    pc = Pc.insert(sess, "00", "hh", utc_datetime(2000, 1, 1), None)
    insert_cops(sess)
    cop = Cop.get_by_code(sess, "5")
    insert_comms(sess)
    comm = Comm.get_by_code(sess, "GSM")
    imp_supplier_contract = Contract.insert_supplier(
        sess,
        "Fusion Supplier 2000",
        participant,
        "",
        {},
        utc_datetime(2000, 1, 1),
        None,
        {},
    )
    dno = participant.insert_party(
        sess, market_role_R, "WPD", utc_datetime(2000, 1, 1), None, "22"
    )
    meter_type = MeterType.insert(sess, "C5", "COP 1-5", utc_datetime(2000, 1, 1), None)
    meter_payment_type = MeterPaymentType.insert(
        sess, "CR", "Credit", utc_datetime(1996, 1, 1), None
    )
    Mtc.insert(
        sess,
        None,
        "845",
        "HH COP5 And Above With Comms",
        False,
        False,
        True,
        meter_type,
        meter_payment_type,
        0,
        utc_datetime(1996, 1, 1),
        None,
    )
    insert_voltage_levels(sess)
    voltage_level = VoltageLevel.get_by_code(sess, "HV")
    dno.insert_llfc(
        sess,
        "510",
        "PC 5-8 & HH HV",
        voltage_level,
        False,
        True,
        utc_datetime(1996, 1, 1),
        None,
    )
    dno.insert_llfc(
        sess,
        "521",
        "Export (HV)",
        voltage_level,
        False,
        False,
        utc_datetime(1996, 1, 1),
        None,
    )
    insert_sources(sess)
    source = Source.get_by_code(sess, "net")
    insert_energisation_statuses(sess)
    energisation_status = EnergisationStatus.get_by_code(sess, "E")
    gsp_group = GspGroup.insert(sess, "_L", "South Western")
    site.insert_e_supply(
        sess,
        source,
        None,
        "Bob",
        utc_datetime(2000, 1, 1),
        None,
        gsp_group,
        mop_contract,
        "773",
        dc_contract,
        "ghyy3",
        "hgjeyhuw",
        pc,
        "845",
        cop,
        comm,
        None,
        energisation_status,
        {},
        "22 7867 6232 781",
        "510",
        imp_supplier_contract,
        "7748",
        361,
        None,
        None,
        None,
        None,
        None,
    )

    site.insert_e_supply(
        sess,
        source,
        None,
        "Dave",
        utc_datetime(2000, 1, 1),
        None,
        gsp_group,
        mop_contract,
        "773",
        dc_contract,
        "ghyy3",
        "hgjeyhuw",
        pc,
        "845",
        cop,
        comm,
        None,
        energisation_status,
        {},
        "22 7868 6232 789",
        "510",
        imp_supplier_contract,
        "7748",
        361,
        None,
        None,
        None,
        None,
        None,
    )
    report_run = ReportRun.insert(
        sess,
        "ecoes_comparison",
        None,
        "ecoes_comparison",
        {},
    )

    sess.commit()
    f = StringIO()
    ecoes_lines = [
        "titles",
        ",".join(
            (
                "2278676232781",
                "address-line-1",
                "address-line-2",
                "address-line-3",
                "address-line-4",
                "address-line-5",
                "address-line-6",
                "address-line-7",
                "address-line-8",
                "address-line-9",
                "post-code",
                "supplier",
                "registration-from",
                "mtc",
                "mtc-date",
                "llfc",
                "llfc-from",
                "pc",
                "",
                "measurement-class",
                "energisation-status",
                "da",
                "dc",
                "mop",
                "mop-appoint-date",
                "gsp-group",
                "gsp-effective-from",
                "dno",
                "msn",
                "meter-install-date",
                "meter-type",
                "map-id",
            ),
        ),
        ",".join(
            (
                "2278686232789",
                "address-line-1",
                "address-line-2",
                "address-line-3",
                "address-line-4",
                "address-line-5",
                "address-line-6",
                "address-line-7",
                "address-line-8",
                "address-line-9",
                "post-code",
                "supplier",
                "registration-from",
                "mtc",
                "mtc-date",
                "llfc",
                "llfc-from",
                "pc",
                "",
                "measurement-class",
                "energisation-status",
                "da",
                "dc",
                "mop",
                "mop-appoint-date",
                "gsp-group",
                "gsp-effective-from",
                "dno",
                "msn",
                "meter-install-date",
                "meter-type",
                "map-id",
            ),
        ),
    ]
    exclude_mpan_cores = []
    ignore_mpan_cores_msn = []
    show_ignored = True

    _process(
        sess,
        ecoes_lines,
        exclude_mpan_cores,
        ignore_mpan_cores_msn,
        f,
        show_ignored,
        report_run,
    )
    expected = [
        [
            "mpan_core",
            "mpan_core_no_spaces",
            "ecoes_pc",
            "chellow_pc",
            "ecoes_mtc",
            "chellow_mtc",
            "ecoes_llfc",
            "chellow_llfc",
            "ecoes_ssc",
            "chellow_ssc",
            "ecoes_es",
            "chellow_es",
            "ecoes_supplier",
            "chellow_supplier",
            "chellow_supplier_contract_name",
            "ecoes_dc",
            "chellow_dc",
            "ecoes_mop",
            "chellow_mop",
            "ecoes_gsp_group",
            "chellow_gsp_group",
            "ecoes_msn",
            "chellow_msn",
            "ecoes_msn_install_date",
            "ecoes_meter_type",
            "chellow_meter_type",
            "ignored",
            "problem",
        ],
        [
            "22 7867 6232 781",
            "2278676232781",
            "pc",
            "00",
            "mtc",
            "845",
            "llfc",
            "510",
            "",
            "",
            "energisation-status",
            "E",
            "supplier",
            "CALB",
            "Fusion Supplier 2000",
            "dc",
            "CALB",
            "mop",
            "CALB",
            "gsp-group",
            "_L",
            "msn",
            "hgjeyhuw",
            "meter-install-date",
            "meter-type",
            "H",
            "False",
            "The energisation statuses don't match. Can't parse the PC. Can't parse "
            "the MTC. The LLFCs don't match. The supplier codes don't match. The DC "
            "codes don't match. The MOP codes don't match. The GSP group codes don't "
            "match. The meter serial numbers don't match. The meter types don't match. "
            "See https://dtc.mrasco.com/DataItem.aspx?ItemCounter=0483 ",
        ],
        [
            "22 7868 6232 789",
            "2278686232789",
            "pc",
            "00",
            "mtc",
            "845",
            "llfc",
            "510",
            "",
            "",
            "energisation-status",
            "E",
            "supplier",
            "CALB",
            "Fusion Supplier 2000",
            "dc",
            "CALB",
            "mop",
            "CALB",
            "gsp-group",
            "_L",
            "msn",
            "hgjeyhuw",
            "meter-install-date",
            "meter-type",
            "H",
            "False",
            "The energisation statuses don't match. Can't parse the PC. Can't parse "
            "the MTC. The LLFCs don't match. The supplier codes don't match. The DC "
            "codes don't match. The MOP codes don't match. The GSP group codes don't "
            "match. The meter serial numbers don't match. The meter types don't match. "
            "See https://dtc.mrasco.com/DataItem.aspx?ItemCounter=0483 ",
        ],
    ]
    assert f.getvalue() == "\n".join(",".join(line) for line in expected) + "\n"
def content(site_id,
            g_supply_id,
            user,
            compression,
            finish_year,
            finish_month,
            months,
            now=None):
    if now is None:
        now = ct_datetime_now()
    report_context = {}
    sess = None
    month_list = list(
        c_months_u(finish_year=finish_year,
                   finish_month=finish_month,
                   months=months))
    start_date, finish_date = month_list[0][0], month_list[-1][-1]

    try:
        sess = Session()
        base_name = [
            "g_monthly_duration",
            hh_format(start_date).replace(" ",
                                          "_").replace(":",
                                                       "").replace("-", ""),
            "for",
            str(months),
            "months",
        ]

        forecast_from = chellow.computer.forecast_date()

        sites = (sess.query(Site).join(SiteGEra).join(GEra).filter(
            SiteGEra.is_physical == true()).distinct().order_by(Site.code))
        if site_id is not None:
            site = Site.get_by_id(sess, site_id)
            sites = sites.filter(Site.id == site.id)
            base_name.append("site")
            base_name.append(site.code)
        if g_supply_id is not None:
            g_supply = GSupply.get_by_id(sess, g_supply_id)
            base_name.append("g_supply")
            base_name.append(str(g_supply.id))
            sites = sites.filter(GEra.g_supply == g_supply)

        running_name, finished_name = chellow.dloads.make_names(
            "_".join(base_name) + ".ods", user)

        rf = open(running_name, "wb")
        site_rows = []
        g_era_rows = []

        era_header_titles = [
            "creation_date",
            "mprn",
            "supply_name",
            "exit_zone",
            "msn",
            "unit",
            "contract",
            "site_id",
            "site_name",
            "associated_site_ids",
            "month",
        ]
        site_header_titles = [
            "creation_date",
            "site_id",
            "site_name",
            "associated_site_ids",
            "month",
        ]
        summary_titles = ["kwh", "gbp", "billed_kwh", "billed_gbp"]

        vb_titles = []
        conts = (sess.query(GContract).join(GEra).join(GSupply).filter(
            GEra.start_date <= finish_date,
            or_(GEra.finish_date == null(), GEra.finish_date >= start_date),
        ).distinct().order_by(GContract.id))
        if g_supply_id is not None:
            conts = conts.filter(GEra.g_supply_id == g_supply_id)
        for cont in conts:
            title_func = chellow.computer.contract_func(
                report_context, cont, "virtual_bill_titles")
            if title_func is None:
                raise Exception("For the contract " + cont.name +
                                " there doesn't seem " +
                                "to be a 'virtual_bill_titles' function.")
            for title in title_func():
                if title not in vb_titles:
                    vb_titles.append(title)

        g_era_rows.append(era_header_titles + summary_titles + vb_titles)
        site_rows.append(site_header_titles + summary_titles)

        for month_start, month_finish in month_list:
            for site in sites.filter(
                    GEra.start_date <= month_finish,
                    or_(GEra.finish_date == null(),
                        GEra.finish_date >= month_start),
            ):
                site_kwh = site_gbp = site_billed_kwh = site_billed_gbp = 0

                for g_era in (sess.query(GEra).join(SiteGEra).filter(
                        SiteGEra.site == site,
                        SiteGEra.is_physical == true(),
                        GEra.start_date <= month_finish,
                        or_(GEra.finish_date == null(),
                            GEra.finish_date >= month_start),
                ).options(
                        joinedload(GEra.g_contract),
                        joinedload(GEra.g_supply),
                        joinedload(GEra.g_supply).joinedload(
                            GSupply.g_exit_zone),
                ).order_by(GEra.id)):

                    g_supply = g_era.g_supply

                    if g_supply_id is not None and g_supply.id != g_supply_id:
                        continue

                    ss_start = hh_max(g_era.start_date, month_start)
                    ss_finish = hh_min(g_era.finish_date, month_finish)

                    ss = GDataSource(
                        sess,
                        ss_start,
                        ss_finish,
                        forecast_from,
                        g_era,
                        report_context,
                        None,
                    )

                    contract = g_era.g_contract
                    vb_function = contract_func(report_context, contract,
                                                "virtual_bill")
                    if vb_function is None:
                        raise BadRequest(
                            "The contract " + contract.name +
                            " doesn't have the virtual_bill() function.")
                    vb_function(ss)
                    bill = ss.bill

                    try:
                        gbp = bill["net_gbp"]
                    except KeyError:
                        gbp = 0
                        bill["problem"] += (
                            "For the supply " + ss.mprn +
                            " the virtual bill " + str(bill) +
                            " from the contract " + contract.name +
                            " does not contain the net_gbp key.")
                    try:
                        kwh = bill["kwh"]
                    except KeyError:
                        kwh = 0
                        bill["problem"] += ("For the supply " + ss.mprn +
                                            " the virtual bill " + str(bill) +
                                            " from the contract " +
                                            contract.name +
                                            " does not contain the 'kwh' key.")

                    billed_kwh = billed_gbp = 0

                    g_era_associates = {
                        s.site.code
                        for s in g_era.site_g_eras if not s.is_physical
                    }

                    for g_bill in sess.query(GBill).filter(
                            GBill.g_supply == g_supply,
                            GBill.start_date <= ss_finish,
                            GBill.finish_date >= ss_start,
                    ):
                        bill_start = g_bill.start_date
                        bill_finish = g_bill.finish_date
                        bill_duration = (bill_finish - bill_start
                                         ).total_seconds() + (30 * 60)
                        overlap_duration = (min(bill_finish, ss_finish) - max(
                            bill_start, ss_start)).total_seconds() + (30 * 60)
                        overlap_proportion = overlap_duration / bill_duration
                        billed_kwh += overlap_proportion * float(g_bill.kwh)
                        billed_gbp += overlap_proportion * float(g_bill.net)

                    associated_site_ids = ",".join(sorted(g_era_associates))
                    g_era_rows.append([
                        make_val(v) for v in [
                            now,
                            g_supply.mprn,
                            g_supply.name,
                            g_supply.g_exit_zone.code,
                            g_era.msn,
                            g_era.g_unit.code,
                            contract.name,
                            site.code,
                            site.name,
                            associated_site_ids,
                            month_finish,
                            kwh,
                            gbp,
                            billed_kwh,
                            billed_gbp,
                        ]
                    ] + [make_val(bill.get(t)) for t in vb_titles])

                    site_kwh += kwh
                    site_gbp += gbp
                    site_billed_kwh += billed_kwh
                    site_billed_gbp += billed_gbp

                linked_sites = ", ".join(s.code
                                         for s in site.find_linked_sites(
                                             sess, month_start, month_finish))

                site_rows.append([
                    make_val(v) for v in [
                        now,
                        site.code,
                        site.name,
                        linked_sites,
                        month_finish,
                        site_kwh,
                        site_gbp,
                        site_billed_kwh,
                        site_billed_gbp,
                    ]
                ])
                sess.rollback()
            write_spreadsheet(rf, compression, site_rows, g_era_rows)

    except BadRequest as e:
        site_rows.append(["Problem " + e.description])
        write_spreadsheet(rf, compression, site_rows, g_era_rows)
    except BaseException:
        msg = traceback.format_exc()
        sys.stderr.write(msg + "\n")
        site_rows.append(["Problem " + msg])
        write_spreadsheet(rf, compression, site_rows, g_era_rows)
    finally:
        if sess is not None:
            sess.close()
        try:
            rf.close()
            os.rename(running_name, finished_name)
        except BaseException:
            msg = traceback.format_exc()
            r_name, f_name = chellow.dloads.make_names("error.txt", user)
            ef = open(r_name, "w")
            ef.write(msg + "\n")
            ef.close()
Пример #21
0
def content(end_year, end_month, months, site_id, sess):
    caches = {}
    try:
        finish_date = Datetime(end_year, end_month, 1, tzinfo=pytz.utc) + \
            relativedelta(months=1) - HH

        start_date = Datetime(end_year, end_month, 1, tzinfo=pytz.utc) - \
            relativedelta(months=months-1)

        forecast_date = chellow.computer.forecast_date()

        site = Site.get_by_id(sess, site_id)

        month_start = start_date
        month_finish = month_start + relativedelta(months=1) - HH
        while not month_finish > finish_date:
            for group in site.groups(sess, month_start, month_finish, True):
                if group.start_date > month_start:
                    chunk_start = group.start_date
                else:
                    chunk_start = month_start
                if group.finish_date > month_finish:
                    chunk_finish = month_finish
                else:
                    chunk_finish = group.finish_date

                displaced_era = chellow.computer.displaced_era(
                    sess, group, chunk_start, chunk_finish)
                if displaced_era is None:
                    continue
                supplier_contract = displaced_era.imp_supplier_contract

                linked_sites = ','.join(
                    a_site.code for a_site in group.sites
                    if not a_site == site)
                generator_types = ' '.join(
                    sorted(
                        [
                            supply.generator_type.code for
                            supply in group.supplies
                            if supply.generator_type is not None]))

                total_gen_breakdown = {}

                results = iter(
                    sess.execute(
                        "select supply.id, hh_datum.value, "
                        "hh_datum.start_date, channel.imp_related, "
                        "source.code, generator_type.code as gen_type_code "
                        "from hh_datum, channel, source, era, supply left "
                        "outer join generator_type on "
                        "supply.generator_type_id = generator_type.id where "
                        "hh_datum.channel_id = channel.id and "
                        "channel.era_id = era.id and era.supply_id = "
                        "supply.id and supply.source_id = source.id and "
                        "channel.channel_type = 'ACTIVE' and not "
                        "(source.code = 'net' and channel.imp_related is "
                        "true) and hh_datum.start_date >= :chunk_start and "
                        "hh_datum.start_date <= :chunk_finish and "
                        "supply.id = any(:supply_ids) order by "
                        "hh_datum.start_date, supply.id",
                        params={
                            'chunk_start': chunk_start,
                            'chunk_finish': chunk_finish,
                            'supply_ids': [s.id for s in group.supplies]}))
                try:
                    res = next(results)
                    hhChannelValue = res.value
                    hhChannelStartDate = res.start_date
                    imp_related = res.imp_related
                    source_code = res.code
                    gen_type = res.gen_type_code
                    hh_date = chunk_start

                    while hh_date <= finish_date:
                        gen_breakdown = {}
                        exported = 0
                        while hhChannelStartDate == hh_date:
                            if not imp_related and source_code in (
                                    'net', 'gen-net'):
                                exported += hhChannelValue
                            if (imp_related and source_code == 'gen') or (
                                    not imp_related and
                                    source_code == 'gen-net'):
                                gen_breakdown[gen_type] = \
                                    gen_breakdown.setdefault(gen_type, 0) + \
                                    hhChannelValue

                            if (not imp_related and source_code == 'gen') or \
                                    (imp_related and source_code == 'gen-net'):
                                gen_breakdown[gen_type] = \
                                    gen_breakdown.setdefault(gen_type, 0) - \
                                    hhChannelValue

                            try:
                                res = next(results)
                                source_code = res.code
                                hhChannelValue = res.value
                                hhChannelStartDate = res.start_date
                                imp_related = res.imp_related
                                gen_type = res.gen_type_code
                            except StopIteration:
                                hhChannelStartDate = None

                        displaced = sum(gen_breakdown.values()) - exported
                        added_so_far = 0
                        for key in sorted(gen_breakdown.keys()):
                            kwh = gen_breakdown[key]
                            if kwh + added_so_far > displaced:
                                total_gen_breakdown[key] = \
                                    total_gen_breakdown.get(key, 0) + \
                                    displaced - added_so_far
                                break
                            else:
                                total_gen_breakdown[key] = \
                                    total_gen_breakdown.get(key, 0) + kwh
                                added_so_far += kwh

                        hh_date += HH
                except StopIteration:
                    pass

                site_ds = chellow.computer.SiteSource(
                    sess, site, chunk_start, chunk_finish, forecast_date, None,
                    caches, displaced_era)
                disp_func = chellow.computer.contract_func(
                    caches, supplier_contract, 'displaced_virtual_bill', None)
                disp_func(site_ds)
                bill = site_ds.supplier_bill

                bill_titles = chellow.computer.contract_func(
                    caches, supplier_contract, 'displaced_virtual_bill_titles',
                    None)()
                yield ','.join(
                    [
                        'Site Code', 'Site Name', 'Associated Site Ids',
                        'From', 'To', 'Gen Types', 'CHP kWh', 'LM kWh',
                        'Turbine kWh', 'PV kWh'] + bill_titles) + '\n'

                yield ','.join('"' + str(value) + '"' for value in [
                    site.code, site.name, linked_sites, hh_format(chunk_start),
                    hh_format(chunk_finish), generator_types] + [
                    total_gen_breakdown.get(t, '') for t in [
                        'chp', 'lm', 'turb', 'pv']])

                for title in bill_titles:
                    if title in bill:
                        v = bill[title]
                        if isinstance(v, Datetime):
                            val = hh_format(v)
                        else:
                            val = str(v)

                        del bill[title]
                    else:
                        val = ''
                    yield ',"' + val + '"'

                for k in sorted(bill.keys()):
                    v = bill[k]
                    if isinstance(v, Datetime):
                        val = hh_format(v)
                    else:
                        val = str(v)
                    yield ',"' + k + '","' + val + '"'
                yield '\n'

            month_start += relativedelta(months=1)
            month_finish = month_start + relativedelta(months=1) - HH

    except:
        yield traceback.format_exc()
Пример #22
0
def test_supply(mocker, sess, client):
    site = Site.insert(sess, "22488", "Water Works")
    g_dn = GDn.insert(sess, "EE", "East of England")
    g_ldz = g_dn.insert_g_ldz(sess, "EA")
    g_exit_zone = g_ldz.insert_g_exit_zone(sess, "EA1")
    insert_g_units(sess)
    g_unit_M3 = GUnit.get_by_code(sess, "M3")
    participant = Participant.insert(sess, "CALB", "AK Industries")
    market_role_Z = MarketRole.get_by_code(sess, "Z")
    participant.insert_party(
        sess, market_role_Z, "None core", utc_datetime(2000, 1, 1), None, None
    )
    g_contract = GContract.insert(
        sess, "Fusion 2020", "", {}, utc_datetime(2000, 1, 1), None, {}
    )
    insert_g_reading_frequencies(sess)
    g_reading_frequency_M = GReadingFrequency.get_by_code(sess, "M")
    msn = "hgeu8rhg"
    g_supply = site.insert_g_supply(
        sess,
        "87614362",
        "main",
        g_exit_zone,
        utc_datetime(2010, 1, 1),
        None,
        msn,
        1,
        g_unit_M3,
        g_contract,
        "d7gthekrg",
        g_reading_frequency_M,
    )
    sess.commit()

    mock_file = StringIO()
    mock_file.close = mocker.Mock()
    mocker.patch(
        "chellow.reports.report_g_supplies_snapshot.open", return_value=mock_file
    )
    mocker.patch(
        "chellow.reports.report_g_supplies_snapshot.chellow.dloads.make_names",
        return_value=("a", "b"),
    )
    mocker.patch("chellow.reports.report_g_supplies_snapshot.os.rename")

    user = mocker.Mock()
    g_supply_id = g_supply.id
    date = utc_datetime(2020, 9, 1)

    chellow.reports.report_g_supplies_snapshot.content(date, g_supply_id, user)

    mock_file.seek(0)
    sheet = csv.reader(mock_file)
    table = list(sheet)

    expected = [
        [
            "Date",
            "Physical Site Id",
            "Physical Site Name",
            "Other Site Ids",
            "Other Site Names",
            "MPRN",
            "Exit Zone",
            "Meter Serial Number",
            "Correction Factor",
            "Unit",
            "Contract",
            "Account",
            "Supply Start",
            "Supply Finish",
        ],
        [
            "2020-09-01 01:00",
            "22488",
            "Water Works",
            "",
            "",
            "87614362",
            "EA1",
            "hgeu8rhg",
            "1",
            "M3",
            "Fusion 2020",
            "d7gthekrg",
            "2010-01-01 00:00",
            "",
        ],
    ]

    assert expected == table
Пример #23
0
def site_content(site_id, start_date, finish_date, user, file_name):
    sess = f = None
    try:
        sess = Session()
        running_name, finished_name = chellow.dloads.make_names(
            file_name, user)
        f = open(running_name, mode='w', newline='')
        writer = csv.writer(f, lineterminator='\n')
        site = Site.get_by_id(sess, site_id)
        sites = sess.query(Site).filter(Site.id == site_id)
        start_date_str = hh_format(start_date)
        finish_date_str = hh_format(finish_date)

        for site in sites:
            writer.writerow(
                [
                    "Site Code", "Site Name", "Associated Site Codes",
                    "Sources", "Generator Types", "From", "To", "Type",
                    "Date"] + list(map(str, range(1, 49))))
            associates = ' '.join(
                s.code for s in site.find_linked_sites(
                    sess, start_date, finish_date))
            source_codes = set()
            gen_types = set()
            for supply in sess.query(Supply).join(Era).join(SiteEra).filter(
                    SiteEra.is_physical == true(), SiteEra.site == site,
                    Era.start_date <= finish_date, or_(
                        Era.finish_date == null(),
                        Era.finish_date >= start_date)).distinct().options(
                            joinedload(Supply.source),
                            joinedload(Supply.generator_type)):
                source_codes.add(supply.source.code)
                gen_type = supply.generator_type
                if gen_type is not None:
                    gen_types.add(gen_type.code)
            source_codes_str = ', '.join(sorted(source_codes))
            gen_types_str = ', '.join(sorted(gen_types))
            vals = None
            for hh in site.hh_data(sess, start_date, finish_date):
                hh_start = hh['start_date']
                if hh_start.hour == 0 and hh_start.minute == 0:
                    if vals is not None:
                        writer.writerow(vals)
                    vals = [
                        site.code, site.name, associates, source_codes_str,
                        gen_types_str, start_date_str, finish_date_str, 'used',
                        hh_start.strftime('%Y-%m-%d')]
                used_gen_kwh = hh['imp_gen'] - hh['exp_net'] - hh['exp_gen']
                used_3p_kwh = hh['imp_3p'] - hh['exp_3p']
                used_kwh = hh['imp_net'] + used_gen_kwh + used_3p_kwh
                vals.append(str(round(used_kwh, 2)))
            if vals is not None:
                writer.writerow(vals)
    except:
        msg = traceback.format_exc()
        sys.stderr.write(msg)
        f.write(msg)
    finally:
        if sess is not None:
            sess.close()
        if f is not None:
            f.close()
            os.rename(running_name, finished_name)
Пример #24
0
def test_batch(mocker, sess, client):
    site = Site.insert(sess, "22488", "Water Works")
    g_dn = GDn.insert(sess, "EE", "East of England")
    g_ldz = g_dn.insert_g_ldz(sess, "EA")
    g_exit_zone = g_ldz.insert_g_exit_zone(sess, "EA1")
    insert_g_units(sess)
    g_unit_M3 = GUnit.get_by_code(sess, "M3")
    participant = Participant.insert(sess, "CALB", "AK Industries")
    market_role_Z = MarketRole.get_by_code(sess, "Z")
    participant.insert_party(sess, market_role_Z, "None core",
                             utc_datetime(2000, 1, 1), None, None)
    g_cv_rate_script = {
        "cvs": {
            "EA": {
                1: {
                    "applicable_at": utc_datetime(2020, 10, 3),
                    "cv": 39.2000
                },
            }
        }
    }
    Contract.insert_non_core(sess, "g_cv", "", {}, utc_datetime(2000, 1, 1),
                             None, g_cv_rate_script)
    bank_holiday_rate_script = {"bank_holidays": []}
    Contract.insert_non_core(
        sess,
        "bank_holidays",
        "",
        {},
        utc_datetime(2000, 1, 1),
        None,
        bank_holiday_rate_script,
    )
    charge_script = """
import chellow.g_ccl
from chellow.g_engine import g_rates
from chellow.utils import reduce_bill_hhs


def virtual_bill_titles():
    return [
        'units_consumed', 'correction_factor', 'unit_code', 'unit_factor',
        'calorific_value', 'kwh', 'gas_rate', 'gas_gbp', 'ccl_rate',
        'standing_rate', 'standing_gbp', 'net_gbp', 'vat_gbp', 'gross_gbp',
        'problem']


def virtual_bill(ds):
    chellow.g_ccl.vb(ds)
    for hh in ds.hh_data:
        start_date = hh['start_date']
        bill_hh = ds.bill_hhs[start_date]
        bill_hh['units_consumed'] = hh['units_consumed']
        bill_hh['correction_factor'] = {hh['correction_factor']}
        bill_hh['unit_code'] = {hh['unit_code']}
        bill_hh['unit_factor'] = {hh['unit_factor']}
        bill_hh['calorific_value'] = {hh['calorific_value']}
        kwh = hh['kwh']
        bill_hh['kwh'] = kwh
        gas_rate = float(
            g_rates(ds.sess, ds.caches, db_id, start_date)['gas_rate'])
        bill_hh['gas_rate'] = {gas_rate}
        bill_hh['gas_gbp'] = gas_rate * kwh
        bill_hh['ccl_kwh'] = kwh
        ccl_rate = hh['ccl']
        bill_hh['ccl_rate'] = {ccl_rate}
        bill_hh['ccl_kwh'] = kwh
        bill_hh['ccl_gbp'] = kwh * ccl_rate
        if hh['utc_is_month_end']:
            standing_rate = float(
                g_rates(
                    ds.sess, ds.caches, db_id, start_date)['standing_rate'])
            bill_hh['standing_rate'] = {standing_rate}
            bill_hh['standing_gbp'] = standing_rate
        if hh['utc_decimal_hour'] == 0:
            pass

        bill_hh['net_gbp'] = sum(
            v for k, v in bill_hh.items() if k.endswith('gbp'))
        bill_hh['vat_gbp'] = 0
        bill_hh['gross_gbp'] = bill_hh['net_gbp'] + bill_hh['vat_gbp']

    ds.bill = reduce_bill_hhs(ds.bill_hhs)
"""
    g_contract_rate_script = {
        "gas_rate": 0.1,
        "standing_rate": 0.1,
    }
    g_contract = GContract.insert(
        sess,
        "Fusion 2020",
        charge_script,
        {},
        utc_datetime(2000, 1, 1),
        None,
        g_contract_rate_script,
    )
    insert_g_reading_frequencies(sess)
    g_reading_frequency_M = GReadingFrequency.get_by_code(sess, "M")
    g_supply = site.insert_g_supply(
        sess,
        "87614362",
        "main",
        g_exit_zone,
        utc_datetime(2018, 1, 1),
        None,
        "hgeu8rhg",
        1,
        g_unit_M3,
        g_contract,
        "d7gthekrg",
        g_reading_frequency_M,
    )
    g_batch = g_contract.insert_g_batch(sess, "b1", "Jan batch")

    breakdown = {"units_consumed": 771}
    insert_bill_types(sess)
    bill_type_n = BillType.get_by_code(sess, "N")
    g_bill = g_batch.insert_g_bill(
        sess,
        g_supply,
        bill_type_n,
        "55h883",
        "dhgh883",
        utc_datetime(2019, 4, 3),
        utc_datetime(2020, 1, 1),
        utc_datetime(2020, 1, 31, 23, 30),
        Decimal("45"),
        Decimal("12.40"),
        Decimal("1.20"),
        Decimal("14.52"),
        "",
        breakdown,
    )
    sess.commit()

    mock_file = StringIO()
    mock_file.close = mocker.Mock()
    mocker.patch("chellow.reports.report_429.open", return_value=mock_file)
    mocker.patch("chellow.reports.report_429.chellow.dloads.make_names",
                 return_value=("a", "b"))
    mocker.patch("chellow.reports.report_429.os.rename")

    user = mocker.Mock()
    chellow.reports.report_429.content(g_batch.id, g_bill.id, user)

    actual = mock_file.getvalue()
    expected = [
        "batch,bill_reference,bill_type,bill_start_date,bill_finish_date,"
        "mprn,supply_name,site_code,site_name,covered_start,covered_finish,"
        "covered_bill_ids,covered_units_consumed,virtual_units_consumed,"
        "covered_correction_factor,virtual_correction_factor,"
        "covered_unit_code,virtual_unit_code,covered_unit_factor,"
        "virtual_unit_factor,covered_calorific_value,virtual_calorific_value,"
        "covered_kwh,virtual_kwh,covered_gas_rate,virtual_gas_rate,"
        "covered_gas_gbp,virtual_gas_gbp,difference_gas_gbp,covered_ccl_rate,"
        "virtual_ccl_rate,covered_standing_rate,virtual_standing_rate,"
        "covered_standing_gbp,virtual_standing_gbp,difference_standing_gbp,"
        "covered_net_gbp,virtual_net_gbp,difference_net_gbp,covered_vat_gbp,"
        "virtual_vat_gbp,difference_vat_gbp,covered_gross_gbp,"
        "virtual_gross_gbp,difference_gross_gbp,covered_problem,"
        "virtual_problem",
        "b1,55h883,N,2020-01-01 00:00,2020-01-31 23:30,87614362,main,22488,"
        "Water Works,2020-01-01 00:00,2020-01-31 23:30,1,771,0,,1.0,,M3,,1.0"
        ",,39.2,45,0.0,,0.1,,0.0,,,0.00339,,0.1,,0.1,,12.40,0.1,12.3,1.20,0,"
        "1.2,14.52,0.1,14.42,,",
    ]
    expected_str = "\r\n".join(expected) + "\r\n"

    assert actual == expected_str
Пример #25
0
def content(year, site_id, user):
    caches = {}
    sess = f = writer = None
    try:
        sess = Session()
        running_name, finished_name = chellow.dloads.make_names(
            'output.csv', user)
        f = open(running_name, mode='w', newline='')
        writer = csv.writer(f, lineterminator='\n')
        writer.writerow(("Site Code", "Site Name", "Displaced TRIAD 1 Date",
                         "Displaced TRIAD 1 MSP kW", "Displaced TRIAD LAF",
                         "Displaced TRIAD 1 GSP kW", "Displaced TRIAD 2 Date",
                         "Displaced TRIAD 2 MSP kW", "Displaced TRIAD 2 LAF",
                         "Displaced TRIAD 2 GSP kW", "Displaced TRIAD 3 Date",
                         "Displaced TRIAD 3 MSP kW", "Displaced TRIAD 3 LAF",
                         "Displaced TRIAD 3 GSP kW", "Displaced GSP kW",
                         "Displaced Rate GBP / kW", "GBP"))

        march_finish = datetime.datetime(year, 4, 1, tzinfo=pytz.utc) - HH
        march_start = datetime.datetime(year, 3, 1, tzinfo=pytz.utc)

        forecast_date = chellow.computer.forecast_date()

        if site_id is None:
            sites = sess.query(Site).join(SiteEra).join(Era).join(Supply).join(
                Source).filter(
                    Source.code.in_(('gen', 'gen-net')),
                    Era.start_date <= march_finish,
                    or_(Era.finish_date == null(),
                        Era.finish_date >= march_start)).distinct()
        else:
            site = Site.get_by_id(sess, site_id)
            sites = sess.query(Site).filter(Site.id == site.id)

        for site in sites.order_by(Site.code):
            displaced_era = chellow.computer.displaced_era(
                sess, caches, site, march_start, march_finish, forecast_date)
            if displaced_era is None:
                continue

            site_ds = chellow.computer.SiteSource(sess, site, march_start,
                                                  march_finish, forecast_date,
                                                  caches, displaced_era)
            chellow.duos.duos_vb(site_ds)
            chellow.triad.hh(site_ds)
            chellow.triad.bill(site_ds)

            bill = site_ds.supplier_bill
            for rname, rset in site_ds.supplier_rate_sets.items():
                if len(rset) == 1:
                    bill[rname] = rset.pop()
            values = [site.code, site.name]
            for i in range(1, 4):
                triad_prefix = 'triad-actual-' + str(i)
                values.append(hh_format(bill[triad_prefix + '-date']))
                for suffix in ['-msp-kw', '-laf', '-gsp-kw']:
                    values.append(bill[triad_prefix + suffix])

            values += [
                str(bill['triad-actual-' + suf])
                for suf in ['gsp-kw', 'rate', 'gbp']
            ]

            writer.writerow(values)

            # Avoid long-running transaction
            sess.rollback()
    except BadRequest as e:
        writer.writerow([e.description])
    except BaseException:
        writer.writerow([traceback.format_exc()])
    finally:
        if sess is not None:
            sess.close()
        if f is not None:
            f.close()
            os.rename(running_name, finished_name)
Пример #26
0
def site_content(site_id, start_date, finish_date, user, file_name):
    sess = f = None
    try:
        sess = Session()
        running_name, finished_name = chellow.dloads.make_names(
            file_name, user)
        f = open(running_name, mode="w", newline="")
        writer = csv.writer(f, lineterminator="\n")
        site = Site.get_by_id(sess, site_id)
        sites = sess.query(Site).filter(Site.id == site_id)
        start_date_str = hh_format(start_date)
        finish_date_str = hh_format(finish_date)

        for site in sites:
            writer.writerow([
                "Site Code",
                "Site Name",
                "Associated Site Codes",
                "Sources",
                "Generator Types",
                "From",
                "To",
                "Type",
                "Date",
            ] + list(map(str, range(1, 51))))
            associates = " ".join(
                s.code
                for s in site.find_linked_sites(sess, start_date, finish_date))
            source_codes = set()
            gen_types = set()
            for supply in (sess.query(Supply).join(Era).join(SiteEra).filter(
                    SiteEra.is_physical == true(),
                    SiteEra.site == site,
                    Era.start_date <= finish_date,
                    or_(Era.finish_date == null(),
                        Era.finish_date >= start_date),
            ).distinct().options(joinedload(Supply.source),
                                 joinedload(Supply.generator_type))):
                source_codes.add(supply.source.code)
                gen_type = supply.generator_type
                if gen_type is not None:
                    gen_types.add(gen_type.code)
            source_codes_str = ", ".join(sorted(source_codes))
            gen_types_str = ", ".join(sorted(gen_types))
            vals = None
            for hh in site.hh_data(sess, start_date, finish_date):
                hh_start_ct = to_ct(hh["start_date"])
                if hh_start_ct.hour == 0 and hh_start_ct.minute == 0:
                    if vals is not None:
                        writer.writerow(vals)
                    vals = [
                        site.code,
                        site.name,
                        associates,
                        source_codes_str,
                        gen_types_str,
                        start_date_str,
                        finish_date_str,
                        "used",
                        hh_start_ct.strftime("%Y-%m-%d"),
                    ]
                used_gen_kwh = hh["imp_gen"] - hh["exp_net"] - hh["exp_gen"]
                used_3p_kwh = hh["imp_3p"] - hh["exp_3p"]
                used_kwh = hh["imp_net"] + used_gen_kwh + used_3p_kwh
                vals.append(str(round(used_kwh, 2)))
            if vals is not None:
                writer.writerow(vals)
    except BaseException:
        msg = traceback.format_exc()
        sys.stderr.write(msg)
        f.write(msg)
    finally:
        if sess is not None:
            sess.close()
        if f is not None:
            f.close()
            os.rename(running_name, finished_name)
Пример #27
0
def test_supply(mocker, sess, client):
    site = Site.insert(sess, "22488", "Water Works")
    g_dn = GDn.insert(sess, "EE", "East of England")
    g_ldz = g_dn.insert_g_ldz(sess, "EA")
    g_exit_zone = g_ldz.insert_g_exit_zone(sess, "EA1")
    insert_g_units(sess)
    g_unit_M3 = GUnit.get_by_code(sess, "M3")
    participant = Participant.insert(sess, "CALB", "AK Industries")
    market_role_Z = MarketRole.get_by_code(sess, "Z")
    participant.insert_party(
        sess, market_role_Z, "None core", utc_datetime(2000, 1, 1), None, None
    )
    g_cv_rate_script = {
        "cvs": {
            "EA": {
                1: {"applicable_at": utc_datetime(2020, 10, 3), "cv": 39.2000},
            }
        }
    }
    Contract.insert_non_core(
        sess, "g_cv", "", {}, utc_datetime(2000, 1, 1), None, g_cv_rate_script
    )
    bank_holiday_rate_script = {"bank_holidays": []}
    Contract.insert_non_core(
        sess,
        "bank_holidays",
        "",
        {},
        utc_datetime(2000, 1, 1),
        None,
        bank_holiday_rate_script,
    )
    charge_script = """
import chellow.g_ccl
from chellow.g_engine import g_rates
from chellow.utils import reduce_bill_hhs


def virtual_bill_titles():
    return [
        'units_consumed', 'correction_factor', 'unit_code', 'unit_factor',
        'calorific_value', 'kwh', 'gas_rate', 'gas_gbp', 'ccl_rate',
        'standing_rate', 'standing_gbp', 'net_gbp', 'vat_gbp', 'gross_gbp',
        'problem']


def virtual_bill(ds):
    chellow.g_ccl.vb(ds)
    for hh in ds.hh_data:
        start_date = hh['start_date']
        bill_hh = ds.bill_hhs[start_date]
        bill_hh['units_consumed'] = hh['units_consumed']
        bill_hh['correction_factor'] = {hh['correction_factor']}
        bill_hh['unit_code'] = {hh['unit_code']}
        bill_hh['unit_factor'] = {hh['unit_factor']}
        bill_hh['calorific_value'] = {hh['calorific_value']}
        kwh = hh['kwh']
        bill_hh['kwh'] = kwh
        gas_rate = float(
            g_rates(ds.sess, ds.caches, db_id, start_date)['gas_rate'])
        bill_hh['gas_rate'] = {gas_rate}
        bill_hh['gas_gbp'] = gas_rate * kwh
        bill_hh['ccl_kwh'] = kwh
        ccl_rate = hh['ccl']
        bill_hh['ccl_rate'] = {ccl_rate}
        bill_hh['ccl_kwh'] = kwh
        bill_hh['ccl_gbp'] = kwh * ccl_rate
        if hh['utc_is_month_end']:
            standing_rate = float(
                g_rates(
                    ds.sess, ds.caches, db_id, start_date)['standing_rate'])
            bill_hh['standing_rate'] = {standing_rate}
            bill_hh['standing_gbp'] = standing_rate
        if hh['utc_decimal_hour'] == 0:
            pass

        bill_hh['net_gbp'] = sum(
            v for k, v in bill_hh.items() if k.endswith('gbp'))
        bill_hh['vat_gbp'] = 0
        bill_hh['gross_gbp'] = bill_hh['net_gbp'] + bill_hh['vat_gbp']

    ds.bill = reduce_bill_hhs(ds.bill_hhs)
"""
    g_contract_rate_script = {
        "gas_rate": 0.1,
        "standing_rate": 0.1,
    }
    g_contract = GContract.insert(
        sess,
        "Fusion 2020",
        charge_script,
        {},
        utc_datetime(2000, 1, 1),
        None,
        g_contract_rate_script,
    )
    insert_g_reading_frequencies(sess)
    g_reading_frequency_M = GReadingFrequency.get_by_code(sess, "M")
    msn = "hgeu8rhg"
    g_supply = site.insert_g_supply(
        sess,
        "87614362",
        "main",
        g_exit_zone,
        utc_datetime(2010, 1, 1),
        None,
        msn,
        1,
        g_unit_M3,
        g_contract,
        "d7gthekrg",
        g_reading_frequency_M,
    )
    g_batch = g_contract.insert_g_batch(sess, "b1", "Jan batch")

    breakdown = {"units_consumed": 771}
    insert_bill_types(sess)
    bill_type_N = BillType.get_by_code(sess, "N")
    insert_g_read_types(sess)
    g_read_type_A = GReadType.get_by_code(sess, "A")
    g_bill = g_batch.insert_g_bill(
        sess,
        g_supply,
        bill_type_N,
        "55h883",
        "dhgh883",
        utc_datetime(2019, 4, 3),
        utc_datetime(2015, 9, 1),
        utc_datetime(2015, 9, 30, 22, 30),
        Decimal("45"),
        Decimal("12.40"),
        Decimal("1.20"),
        Decimal("14.52"),
        "",
        breakdown,
    )
    g_bill.insert_g_read(
        sess,
        msn,
        g_unit_M3,
        Decimal("1"),
        Decimal("37"),
        Decimal("90"),
        utc_datetime(2015, 9, 1),
        g_read_type_A,
        Decimal("890"),
        utc_datetime(2015, 9, 25),
        g_read_type_A,
    )
    sess.commit()

    mock_file = StringIO()
    mock_file.close = mocker.Mock()
    mocker.patch(
        "chellow.reports.report_g_virtual_bills_hh.open", return_value=mock_file
    )
    mocker.patch(
        "chellow.reports.report_g_virtual_bills_hh.chellow.dloads.make_names",
        return_value=("a", "b"),
    )
    mocker.patch("chellow.reports.report_g_virtual_bills.os.rename")

    user = mocker.Mock()
    g_supply_id = g_supply.id
    start_date = to_utc(ct_datetime(2018, 2, 1))
    finish_date = to_utc(ct_datetime(2018, 2, 1, 0, 30))

    chellow.reports.report_g_virtual_bills_hh.content(
        g_supply_id, start_date, finish_date, user
    )

    mock_file.seek(0)
    table = list(csv.reader(mock_file))

    expected = [
        [
            "MPRN",
            "Site Code",
            "Site Name",
            "Account",
            "HH Start",
            "",
            "",
            "units_consumed",
            "correction_factor",
            "unit_code",
            "unit_factor",
            "calorific_value",
            "kwh",
            "gas_rate",
            "gas_gbp",
            "ccl_rate",
            "standing_rate",
            "standing_gbp",
            "net_gbp",
            "vat_gbp",
            "gross_gbp",
            "problem",
        ],
        [
            "87614362",
            "22488",
            "Water Works",
            "d7gthekrg",
            "2018-02-01 00:00",
            "",
            "",
            "0.6944444444444444",
            "1.0",
            "M3",
            "1.0",
            "39.2",
            "7.561728395061729",
            "0.1",
            "0.7561728395061729",
            "0.00198",
            "",
            "",
            "0.7711450617283951",
            "0",
            "0.7711450617283951",
            "",
            "ccl_gbp",
            "0.014972222222222222",
            "ccl_kwh",
            "7.561728395061729",
        ],
        [
            "87614362",
            "22488",
            "Water Works",
            "d7gthekrg",
            "2018-02-01 00:30",
            "",
            "",
            "0.6944444444444444",
            "1.0",
            "M3",
            "1.0",
            "39.2",
            "7.561728395061729",
            "0.1",
            "0.7561728395061729",
            "0.00198",
            "",
            "",
            "0.7711450617283951",
            "0",
            "0.7711450617283951",
            "",
            "ccl_gbp",
            "0.014972222222222222",
            "ccl_kwh",
            "7.561728395061729",
        ],
    ]

    match_tables(table, expected)
Пример #28
0
def test_get_era_bundles_bill_after_supply_end(sess, client):
    """Check that a bill starting after the end of a supply still gets
    shown.
    """
    site = Site.insert(sess, "22488", "Water Works")
    insert_sources(sess)
    source = Source.get_by_code(sess, "net")
    gsp_group = GspGroup.insert(sess, "_L", "South Western")
    participant = Participant.insert(sess, "hhak", "AK Industries")
    market_role_X = MarketRole.insert(sess, "X", "Supplier")
    market_role_M = MarketRole.insert(sess, "M", "Mop")
    market_role_C = MarketRole.insert(sess, "C", "HH Dc")
    market_role_R = MarketRole.insert(sess, "R", "Distributor")
    participant.insert_party(sess, market_role_M, "Fusion Mop Ltd",
                             utc_datetime(2000, 1, 1), None, None)
    participant.insert_party(sess, market_role_X, "Fusion Ltc",
                             utc_datetime(2000, 1, 1), None, None)
    participant.insert_party(sess, market_role_C, "Fusion DC",
                             utc_datetime(2000, 1, 1), None, None)
    mop_contract = Contract.insert_mop(sess, "Fusion", participant, "", {},
                                       utc_datetime(2000, 1, 1), None, {})
    dc_contract = Contract.insert_hhdc(sess, "Fusion DC 2000", participant, "",
                                       {}, utc_datetime(2000, 1, 1), None, {})
    pc = Pc.insert(sess, "00", "hh", utc_datetime(2000, 1, 1), None)
    insert_cops(sess)
    cop = Cop.get_by_code(sess, "5")
    imp_supplier_contract = Contract.insert_supplier(
        sess,
        "Fusion Supplier 2000",
        participant,
        "",
        {},
        utc_datetime(2000, 1, 1),
        None,
        {},
    )
    dno = participant.insert_party(sess, market_role_R, "WPD",
                                   utc_datetime(2000, 1, 1), None, "22")
    meter_type = MeterType.insert(sess, "C5", "COP 1-5",
                                  utc_datetime(2000, 1, 1), None)
    meter_payment_type = MeterPaymentType.insert(sess, "CR", "Credit",
                                                 utc_datetime(1996, 1, 1),
                                                 None)
    Mtc.insert(
        sess,
        None,
        "845",
        "HH COP5 And Above With Comms",
        False,
        False,
        True,
        meter_type,
        meter_payment_type,
        0,
        utc_datetime(1996, 1, 1),
        None,
    )
    insert_voltage_levels(sess)
    voltage_level = VoltageLevel.get_by_code(sess, "HV")
    dno.insert_llfc(
        sess,
        "510",
        "PC 5-8 & HH HV",
        voltage_level,
        False,
        True,
        utc_datetime(1996, 1, 1),
        None,
    )
    insert_energisation_statuses(sess)
    energisation_status = EnergisationStatus.get_by_code(sess, "E")
    supply = site.insert_e_supply(
        sess,
        source,
        None,
        "Bob",
        utc_datetime(2020, 1, 1),
        utc_datetime(2020, 1, 31),
        gsp_group,
        mop_contract,
        "773",
        dc_contract,
        "ghyy3",
        "hgjeyhuw",
        pc,
        "845",
        cop,
        None,
        energisation_status,
        {},
        "22 7867 6232 781",
        "510",
        imp_supplier_contract,
        "7748",
        361,
        None,
        None,
        None,
        None,
        None,
    )
    batch = imp_supplier_contract.insert_batch(sess, "b1", "batch 1")
    insert_bill_types(sess)
    bill_type_N = BillType.get_by_code(sess, "N")
    batch.insert_bill(
        sess,
        "ytgeklf",
        "s77349",
        utc_datetime(2020, 2, 10),
        utc_datetime(2020, 2, 2),
        utc_datetime(2020, 3, 1),
        Decimal(0),
        Decimal("0.00"),
        Decimal("0.00"),
        Decimal("0.00"),
        bill_type_N,
        {},
        supply,
    )
    sess.commit()

    bundles = get_era_bundles(sess, supply)

    assert len(bundles[0]["imp_bills"]["bill_dicts"]) == 1
Пример #29
0
def content(scenario_props, scenario_id, base_name, site_id, supply_id, user):
    now = Datetime.now(pytz.utc)
    report_context = {}
    future_funcs = {}
    report_context['future_funcs'] = future_funcs

    sess = None
    try:
        sess = Session()
        if scenario_props is None:
            scenario_contract = Contract.get_supplier_by_id(sess, scenario_id)
            scenario_props = scenario_contract.make_properties()
            base_name.append(scenario_contract.name)

        for contract in sess.query(Contract).join(MarketRole).filter(
                MarketRole.code == 'Z'):
            try:
                props = scenario_props[contract.name]
            except KeyError:
                continue

            try:
                rate_start = props['start_date']
            except KeyError:
                raise BadRequest(
                    "In " + scenario_contract.name + " for the rate " +
                    contract.name + " the start_date is missing.")

            if rate_start is not None:
                rate_start = rate_start.replace(tzinfo=pytz.utc)

            lib = importlib.import_module('chellow.' + contract.name)

            if hasattr(lib, 'create_future_func'):
                future_funcs[contract.id] = {
                    'start_date': rate_start,
                    'func': lib.create_future_func(
                        props['multiplier'], props['constant'])}

        start_date = scenario_props['scenario_start']
        if start_date is None:
            start_date = Datetime(
                now.year, now.month, 1, tzinfo=pytz.utc)
        else:
            start_date = start_date.replace(tzinfo=pytz.utc)

        base_name.append(
            hh_format(start_date).replace(' ', '_').replace(':', '').
            replace('-', ''))
        months = scenario_props['scenario_duration']
        base_name.append('for')
        base_name.append(str(months))
        base_name.append('months')
        finish_date = start_date + relativedelta(months=months)

        if 'kwh_start' in scenario_props:
            kwh_start = scenario_props['kwh_start']
        else:
            kwh_start = None

        if kwh_start is None:
            kwh_start = chellow.computer.forecast_date()
        else:
            kwh_start = kwh_start.replace(tzinfo=pytz.utc)

        sites = sess.query(Site).join(SiteEra).join(Era).filter(
            Era.start_date <= finish_date,
            or_(
                Era.finish_date == null(),
                Era.finish_date >= start_date)).distinct().order_by(Site.code)
        if site_id is not None:
            site = Site.get_by_id(sess, site_id)
            sites = sites.filter(Site.id == site.id)
            base_name.append('site')
            base_name.append(site.code)
        if supply_id is not None:
            supply = Supply.get_by_id(sess, supply_id)
            base_name.append('supply')
            base_name.append(str(supply.id))
            sites = sites.filter(Era.supply == supply)

        running_name, finished_name = chellow.dloads.make_names(
            '_'.join(base_name) + '.ods', user)

        rf = open(running_name, "wb")
        f = odswriter.writer(rf, '1.1')
        group_tab = f.new_sheet("Site Level")
        sup_tab = f.new_sheet("Supply Level")
        changes = defaultdict(list, {})

        try:
            kw_changes = scenario_props['kw_changes']
        except KeyError:
            kw_changes = ''

        for row in csv.reader(io.StringIO(kw_changes)):
            if len(''.join(row).strip()) == 0:
                continue
            if len(row) != 4:
                raise BadRequest(
                    "Can't interpret the row " + str(row) + " it should be of "
                    "the form SITE_CODE, USED / GENERATED, DATE, MULTIPLIER")
            site_code, typ, date_str, kw_str = row
            date = Datetime.strptime(date_str.strip(), "%Y-%m-%d").replace(
                tzinfo=pytz.utc)
            changes[site_code.strip()].append(
                {
                    'type': typ.strip(), 'date': date,
                    'multiplier': float(kw_str)})

        sup_header_titles = [
            'imp-mpan-core', 'exp-mpan-core', 'metering-type', 'source',
            'generator-type', 'supply-name', 'msn', 'pc', 'site-id',
            'site-name', 'associated-site-ids', 'month']
        site_header_titles = [
            'site-id', 'site-name', 'associated-site-ids', 'month',
            'metering-type', 'sources', 'generator-types']
        summary_titles = [
            'import-net-kwh', 'export-net-kwh', 'import-gen-kwh',
            'export-gen-kwh', 'import-3rd-party-kwh', 'export-3rd-party-kwh',
            'displaced-kwh', 'used-kwh', 'used-3rd-party-kwh',
            'import-net-gbp', 'export-net-gbp', 'import-gen-gbp',
            'export-gen-gbp', 'import-3rd-party-gbp', 'export-3rd-party-gbp',
            'displaced-gbp', 'used-gbp', 'used-3rd-party-gbp',
            'billed-import-net-kwh', 'billed-import-net-gbp']

        title_dict = {}
        for cont_type, con_attr in (
                ('mop', Era.mop_contract), ('dc', Era.hhdc_contract),
                ('imp-supplier', Era.imp_supplier_contract),
                ('exp-supplier', Era.exp_supplier_contract)):
            titles = []
            title_dict[cont_type] = titles
            conts = sess.query(Contract).join(con_attr) \
                .join(Era.supply).join(Source).filter(
                    Era.start_date <= start_date,
                    or_(
                        Era.finish_date == null(),
                        Era.finish_date >= start_date),
                    Source.code.in_(('net', '3rd-party'))
                ).distinct().order_by(Contract.id)
            if supply_id is not None:
                conts = conts.filter(Era.supply_id == supply_id)
            for cont in conts:
                title_func = chellow.computer.contract_func(
                    report_context, cont, 'virtual_bill_titles', None)
                if title_func is None:
                    raise Exception(
                        "For the contract " + cont.name +
                        " there doesn't seem to be a "
                        "'virtual_bill_titles' function.")
                for title in title_func():
                    if title not in titles:
                        titles.append(title)

        sup_tab.writerow(
            sup_header_titles + summary_titles + [None] +
            ['mop-' + t for t in title_dict['mop']] +
            [None] + ['dc-' + t for t in title_dict['dc']] + [None] +
            ['imp-supplier-' + t for t in title_dict['imp-supplier']] +
            [None] + ['exp-supplier-' + t for t in title_dict['exp-supplier']])
        group_tab.writerow(site_header_titles + summary_titles)

        sites = sites.all()
        month_start = start_date
        while month_start < finish_date:
            month_finish = month_start + relativedelta(months=1) - HH
            for site in sites:
                site_changes = changes[site.code]
                site_associates = set()
                site_category = None
                site_sources = set()
                site_gen_types = set()
                site_month_data = defaultdict(int)
                for group in site.groups(
                        sess, month_start, month_finish, False):
                    site_associates.update(
                        set(
                            s.code for s in group.sites
                            if s.code != site.code))
                    for cand_supply in group.supplies:
                        site_sources.add(cand_supply.source.code)
                        if cand_supply.generator_type is not None:
                            site_gen_types.add(cand_supply.generator_type.code)
                        for cand_era in sess.query(Era).filter(
                                Era.supply == cand_supply,
                                Era.start_date <= group.finish_date, or_(
                                    Era.finish_date == null(),
                                    Era.finish_date >= group.start_date)). \
                                options(
                                    joinedload(Era.channels),
                                    joinedload(Era.pc),
                                    joinedload(Era.mtc).joinedload(
                                        Mtc.meter_type)):
                            if site_category != 'hh':
                                if cand_era.pc.code == '00':
                                    site_category = 'hh'
                                elif site_category != 'amr':
                                    if len(cand_era.channels) > 0:
                                        site_category = 'amr'
                                    elif site_category != 'nhh':
                                        if cand_era.mtc.meter_type.code \
                                                not in ['UM', 'PH']:
                                            site_category = 'nhh'
                                        else:
                                            site_category = 'unmetered'

                for group in site.groups(
                        sess, month_start, month_finish, True):
                    calcs = []
                    deltas = defaultdict(int)
                    group_associates = set(
                        s.code for s in group.sites if s.code != site.code)
                    for supply in group.supplies:
                        if supply_id is not None and supply.id != supply_id:
                            continue
                        for era in sess.query(Era).join(Supply) \
                                .join(Source).filter(
                                    Era.supply == supply,
                                    Era.start_date <= group.finish_date, or_(
                                        Era.finish_date == null(),
                                        Era.finish_date >= group.start_date)) \
                                .options(
                                    joinedload(Era.ssc),
                                    joinedload(Era.hhdc_contract),
                                    joinedload(Era.mop_contract),
                                    joinedload(Era.imp_supplier_contract),
                                    joinedload(Era.exp_supplier_contract),
                                    joinedload(Era.channels),
                                    joinedload(Era.imp_llfc).joinedload(
                                        Llfc.voltage_level),
                                    joinedload(Era.exp_llfc).joinedload(
                                        Llfc.voltage_level),
                                    joinedload(Era.cop),
                                    joinedload(Era.supply).joinedload(
                                        Supply.dno_contract),
                                    joinedload(Era.mtc).joinedload(
                                        Mtc.meter_type)):

                            if era.start_date > group.start_date:
                                ss_start = era.start_date
                            else:
                                ss_start = group.start_date

                            if hh_before(era.finish_date, group.finish_date):
                                ss_finish = era.finish_date
                            else:
                                ss_finish = group.finish_date

                            if era.imp_mpan_core is None:
                                imp_ss = None
                            else:
                                imp_ss = SupplySource(
                                    sess, ss_start, ss_finish, kwh_start, era,
                                    True, None, report_context)

                            if era.exp_mpan_core is None:
                                exp_ss = None
                                measurement_type = imp_ss.measurement_type
                            else:
                                exp_ss = SupplySource(
                                    sess, ss_start, ss_finish, kwh_start, era,
                                    False, None, report_context)
                                measurement_type = exp_ss.measurement_type

                            order = meter_order[measurement_type]
                            calcs.append(
                                (
                                    order, era.imp_mpan_core,
                                    era.exp_mpan_core, imp_ss, exp_ss))

                            if imp_ss is not None and len(era.channels) == 0:
                                for hh in imp_ss.hh_data:
                                    deltas[hh['start-date']] += hh['msp-kwh']

                    imp_net_delts = defaultdict(int)
                    exp_net_delts = defaultdict(int)
                    imp_gen_delts = defaultdict(int)

                    displaced_era = chellow.computer.displaced_era(
                        sess, group, group.start_date, group.finish_date)
                    site_ds = chellow.computer.SiteSource(
                        sess, site, group.start_date, group.finish_date,
                        kwh_start, None, report_context, displaced_era)

                    for hh in site_ds.hh_data:
                        try:
                            delta = deltas[hh['start-date']]
                            hh['import-net-kwh'] += delta
                            hh['used-kwh'] += delta
                        except KeyError:
                            pass

                    for hh in site_ds.hh_data:
                        for change in site_changes:
                            if change['type'] == 'used' and \
                                    change['date'] <= hh['start-date']:
                                used = change['multiplier'] * hh['used-kwh']
                                exp_net = max(
                                    0, hh['import-gen-kwh'] -
                                    hh['export-gen-kwh'] -
                                    used)
                                exp_net_delt = exp_net - hh['export-net-kwh']
                                exp_net_delts[hh['start-date']] += exp_net_delt
                                displaced = hh['import-gen-kwh'] - \
                                    hh['export-gen-kwh'] - exp_net
                                imp_net = used - displaced
                                imp_delt = imp_net - hh['import-net-kwh']
                                imp_net_delts[hh['start-date']] += imp_delt

                                hh['import-net-kwh'] = imp_net
                                hh['used-kwh'] = used
                                hh['export-net-kwh'] = exp_net
                                hh['msp-kwh'] = displaced
                            elif change['type'] == 'generated' and \
                                    change['date'] <= hh['start-date']:
                                imp_gen = change['multiplier'] * \
                                    hh['import-gen-kwh']
                                imp_gen_delt = imp_gen - hh['import-gen-kwh']
                                exp_net = max(
                                    0, imp_gen - hh['export-gen-kwh'] -
                                    hh['used-kwh'])
                                exp_net_delt = exp_net - hh['export-net-kwh']
                                exp_net_delts[hh['start-date']] += exp_net_delt

                                displaced = imp_gen - hh['export-gen-kwh'] - \
                                    exp_net

                                imp_net = hh['used-kwh'] - displaced
                                imp_net_delt = imp_net - hh['import-net-kwh']
                                imp_net_delts[hh['start-date']] += imp_net_delt

                                imp_gen_delts[hh['start-date']] += imp_gen_delt

                                hh['import-net-kwh'] = imp_net
                                hh['export-net-kwh'] = exp_net
                                hh['import-gen-kwh'] = imp_gen
                                hh['msp-kwh'] = displaced

                    if displaced_era is not None and supply_id is None:
                        month_data = {}
                        for sname in (
                                'import-net', 'export-net', 'import-gen',
                                'export-gen', 'import-3rd-party',
                                'export-3rd-party', 'msp', 'used',
                                'used-3rd-party', 'billed-import-net'):
                            for xname in ('kwh', 'gbp'):
                                month_data[sname + '-' + xname] = 0

                        month_data['used-kwh'] = \
                            month_data['displaced-kwh'] = \
                            sum(hh['msp-kwh'] for hh in site_ds.hh_data)

                        disp_supplier_contract = \
                            displaced_era.imp_supplier_contract
                        disp_vb_function = chellow.computer.contract_func(
                            report_context, disp_supplier_contract,
                            'displaced_virtual_bill', None)
                        if disp_vb_function is None:
                            raise BadRequest(
                                "The supplier contract " +
                                disp_supplier_contract.name +
                                " doesn't have the displaced_virtual_bill() "
                                "function.")
                        disp_vb_function(site_ds)
                        disp_supplier_bill = site_ds.supplier_bill

                        try:
                            gbp = disp_supplier_bill['net-gbp']
                        except KeyError:
                            disp_supplier_bill['problem'] += \
                                'For the supply ' + \
                                site_ds.mpan_core + \
                                ' the virtual bill ' + \
                                str(disp_supplier_bill) + \
                                ' from the contract ' + \
                                disp_supplier_contract.name + \
                                ' does not contain the net-gbp key.'

                        month_data['used-gbp'] = \
                            month_data['displaced-gbp'] = \
                            site_ds.supplier_bill['net-gbp']

                        out = [
                            None, None, displaced_era.make_meter_category(),
                            'displaced', None, None, None, None, site.code,
                            site.name,
                            ','.join(sorted(list(group_associates))),
                            month_finish] + \
                            [month_data[t] for t in summary_titles]

                        sup_tab.writerow(out)
                        for k, v in month_data.items():
                            site_month_data[k] += v
                    for i, (
                            order, imp_mpan_core, exp_mpan_core, imp_ss,
                            exp_ss) in enumerate(sorted(calcs, key=str)):
                        if imp_ss is None:
                            era = exp_ss.era
                        else:
                            era = imp_ss.era
                        supply = era.supply
                        source = supply.source
                        source_code = source.code
                        site_sources.add(source_code)
                        month_data = {}
                        for name in (
                                'import-net', 'export-net', 'import-gen',
                                'export-gen', 'import-3rd-party',
                                'export-3rd-party', 'displaced', 'used',
                                'used-3rd-party', 'billed-import-net'):
                            for sname in ('kwh', 'gbp'):
                                month_data[name + '-' + sname] = 0

                        if source_code == 'net':
                            delts = imp_net_delts
                        elif source_code == 'gen':
                            delts = imp_gen_delts
                        else:
                            delts = []

                        if len(delts) > 0 and imp_ss is not None:
                            for hh in imp_ss.hh_data:
                                diff = hh['msp-kwh'] + delts[hh['start-date']]
                                if diff < 0:
                                    hh['msp-kwh'] = 0
                                    hh['msp-kw'] = 0
                                    delts[hh['start-date']] -= hh['msp-kwh']
                                else:
                                    hh['msp-kwh'] += delts[hh['start-date']]
                                    hh['msp-kw'] += hh['msp-kwh'] / 2
                                    del delts[hh['start-date']]

                            left_kwh = sum(delts.values())
                            if left_kwh > 0:
                                first_hh = imp_ss.hh_data[0]
                                first_hh['msp-kwh'] += left_kwh
                                first_hh['msp-kw'] += left_kwh / 2

                        imp_supplier_contract = era.imp_supplier_contract
                        if imp_supplier_contract is not None:
                            import_vb_function = contract_func(
                                report_context, imp_supplier_contract,
                                'virtual_bill', None)
                            if import_vb_function is None:
                                raise BadRequest(
                                    "The supplier contract " +
                                    imp_supplier_contract.name +
                                    " doesn't have the virtual_bill() "
                                    "function.")
                            import_vb_function(imp_ss)
                            imp_supplier_bill = imp_ss.supplier_bill

                            try:
                                gbp = imp_supplier_bill['net-gbp']
                            except KeyError:
                                imp_supplier_bill['problem'] += \
                                    'For the supply ' + \
                                    imp_ss.mpan_core + \
                                    ' the virtual bill ' + \
                                    str(imp_supplier_bill) + \
                                    ' from the contract ' + \
                                    imp_supplier_contract.name + \
                                    ' does not contain the net-gbp key.'
                            if source_code in ('net', 'gen-net'):
                                month_data['import-net-gbp'] += gbp
                                month_data['used-gbp'] += gbp
                            elif source_code == '3rd-party':
                                month_data['import-3rd-party-gbp'] += gbp
                                month_data['used-gbp'] += gbp
                            elif source_code == '3rd-party-reverse':
                                month_data['export-3rd-party-gbp'] += gbp
                                month_data['used-gbp'] -= gbp

                            kwh = sum(
                                hh['msp-kwh'] for hh in imp_ss.hh_data)

                            if source_code in ('net', 'gen-net'):
                                month_data['import-net-kwh'] += kwh
                                month_data['used-kwh'] += kwh
                            elif source_code == '3rd-party':
                                month_data['import-3rd-party-kwh'] += kwh
                                month_data['used-kwh'] += kwh
                            elif source_code == '3rd-party-reverse':
                                month_data['export-3rd-party-kwh'] += kwh
                                month_data['used-kwh'] -= kwh
                            elif source_code in ('gen', 'gen-net'):
                                month_data['import-gen-kwh'] += kwh

                        exp_supplier_contract = era.exp_supplier_contract
                        if exp_supplier_contract is None:
                            kwh = sess.query(
                                func.coalesce(
                                    func.sum(
                                        cast(HhDatum.value, Float)), 0)). \
                                join(Channel).filter(
                                    Channel.era == era,
                                    Channel.channel_type == 'ACTIVE',
                                    Channel.imp_related == false()).scalar()
                            if source_code == 'gen':
                                month_data['export-net-kwh'] += kwh
                        else:
                            export_vb_function = contract_func(
                                report_context, exp_supplier_contract,
                                'virtual_bill', None)
                            export_vb_function(exp_ss)

                            exp_supplier_bill = exp_ss.supplier_bill
                            try:
                                gbp = exp_supplier_bill['net-gbp']
                            except KeyError:
                                exp_supplier_bill['problem'] += \
                                    'For the supply ' + \
                                    imp_ss.mpan_core + \
                                    ' the virtual bill ' + \
                                    str(imp_supplier_bill) + \
                                    ' from the contract ' + \
                                    imp_supplier_contract.name + \
                                    ' does not contain the net-gbp key.'

                            kwh = sum(hh['msp-kwh'] for hh in exp_ss.hh_data)

                            if source_code in ('net', 'gen-net'):
                                month_data['export-net-kwh'] += kwh
                                month_data['export-net-gbp'] += gbp
                            elif source_code in \
                                    ('3rd-party', '3rd-party-reverse'):
                                month_data['export-3rd-party-kwh'] += kwh
                                month_data['export-3rd-party-gbp'] += gbp
                                month_data['used-kwh'] -= kwh
                                month_data['used-gbp'] -= gbp
                            elif source_code == 'gen':
                                month_data['export-gen-kwh'] += kwh

                        sss = exp_ss if imp_ss is None else imp_ss
                        dc_contract = era.hhdc_contract
                        sss.contract_func(
                            dc_contract, 'virtual_bill')(sss)
                        dc_bill = sss.dc_bill
                        gbp = dc_bill['net-gbp']

                        mop_contract = era.mop_contract
                        mop_bill_function = sss.contract_func(
                            mop_contract, 'virtual_bill')
                        mop_bill_function(sss)
                        mop_bill = sss.mop_bill
                        gbp += mop_bill['net-gbp']

                        if source_code in ('3rd-party', '3rd-party-reverse'):
                            month_data['import-3rd-party-gbp'] += gbp
                        else:
                            month_data['import-net-gbp'] += gbp
                        month_data['used-gbp'] += gbp

                        if source_code in ('gen', 'gen-net'):
                            generator_type = supply.generator_type.code
                            site_gen_types.add(generator_type)
                        else:
                            generator_type = None

                        sup_category = era.make_meter_category()
                        if CATEGORY_ORDER[site_category] < \
                                CATEGORY_ORDER[sup_category]:
                            site_category = sup_category

                        for bill in sess.query(Bill).filter(
                                Bill.supply == supply,
                                Bill.start_date <= sss.finish_date,
                                Bill.finish_date >= sss.start_date):
                            bill_start = bill.start_date
                            bill_finish = bill.finish_date
                            bill_duration = (
                                bill_finish - bill_start).total_seconds() + \
                                (30 * 60)
                            overlap_duration = (
                                min(bill_finish, sss.finish_date) -
                                max(bill_start, sss.start_date)
                                ).total_seconds() + (30 * 60)
                            overlap_proportion = \
                                float(overlap_duration) / bill_duration
                            month_data['billed-import-net-kwh'] += \
                                overlap_proportion * float(bill.kwh)
                            month_data['billed-import-net-gbp'] += \
                                overlap_proportion * float(bill.net)

                        out = [
                            era.imp_mpan_core, era.exp_mpan_core,
                            sup_category, source_code,
                            generator_type, supply.name, era.msn, era.pc.code,
                            site.code, site.name,
                            ','.join(sorted(list(site_associates))),
                            month_finish] + [
                            month_data[t] for t in summary_titles] + [None] + [
                            (mop_bill[t] if t in mop_bill else None)
                            for t in title_dict['mop']] + [None] + \
                            [(dc_bill[t] if t in dc_bill else None)
                                for t in title_dict['dc']]
                        if imp_supplier_contract is None:
                            out += [None] * \
                                (len(title_dict['imp-supplier']) + 1)
                        else:
                            out += [None] + [
                                (
                                    imp_supplier_bill[t]
                                    if t in imp_supplier_bill else None)
                                for t in title_dict['imp-supplier']]
                        if exp_supplier_contract is not None:
                            out += [None] + [
                                (
                                    exp_supplier_bill[t]
                                    if t in exp_supplier_bill else None)
                                for t in title_dict['exp-supplier']]

                        for k, v in month_data.items():
                            site_month_data[k] += v
                        sup_tab.writerow(out)

                group_tab.writerow(
                    [
                        site.code, site.name,
                        ''.join(sorted(list(site_associates))),
                        month_finish, site_category,
                        ', '.join(sorted(list(site_sources))),
                        ', '.join(sorted(list(site_gen_types)))] +
                    [site_month_data[k] for k in summary_titles])
                sess.rollback()

            month_start += relativedelta(months=1)
    except BadRequest as e:
        msg = e.description + traceback.format_exc()
        sys.stderr.write(msg + '\n')
        group_tab.writerow(["Problem " + msg])
    except:
        msg = traceback.format_exc()
        sys.stderr.write(msg + '\n')
        group_tab.writerow(["Problem " + msg])
    finally:
        if sess is not None:
            sess.close()
        try:
            f.close()
            rf.close()
            os.rename(running_name, finished_name)
        except:
            msg = traceback.format_exc()
            r_name, f_name = chellow.dloads.make_names('error.txt', user)
            ef = open(r_name, "w")
            ef.write(msg + '\n')
            ef.close()
Пример #30
0
def content(year, site_id, user):
    caches = {}
    sess = f = writer = None
    try:
        sess = Session()
        running_name, finished_name = chellow.dloads.make_names(
            'output.csv', user)
        f = open(running_name, mode='w', newline='')
        writer = csv.writer(f, lineterminator='\n')
        writer.writerow(
            (
                "Site Code", "Site Name", "Displaced TRIAD 1 Date",
                "Displaced TRIAD 1 MSP kW", "Displaced TRIAD LAF",
                "Displaced TRIAD 1 GSP kW", "Displaced TRIAD 2 Date",
                "Displaced TRIAD 2 MSP kW", "Displaced TRIAD 2 LAF",
                "Displaced TRIAD 2 GSP kW", "Displaced TRIAD 3 Date",
                "Displaced TRIAD 3 MSP kW", "Displaced TRIAD 3 LAF",
                "Displaced TRIAD 3 GSP kW", "Displaced GSP kW",
                "Displaced Rate GBP / kW", "GBP"))

        march_finish = datetime.datetime(year, 4, 1, tzinfo=pytz.utc) - HH
        march_start = datetime.datetime(year, 3, 1, tzinfo=pytz.utc)

        forecast_date = chellow.computer.forecast_date()

        if site_id is None:
            sites = sess.query(Site).join(SiteEra).join(Era).join(Supply).join(
                Source).filter(
                Source.code.in_(('gen', 'gen-net')),
                Era.start_date <= march_finish,
                or_(
                    Era.finish_date == null(),
                    Era.finish_date >= march_start)).distinct()
        else:
            site = Site.get_by_id(sess, site_id)
            sites = sess.query(Site).filter(Site.id == site.id)

        for site in sites.order_by(Site.code):
            displaced_era = chellow.computer.displaced_era(
                sess, caches, site, march_start, march_finish, forecast_date)
            if displaced_era is None:
                continue

            site_ds = chellow.computer.SiteSource(
                sess, site, march_start, march_finish, forecast_date, caches,
                displaced_era)
            chellow.duos.duos_vb(site_ds)
            chellow.triad.hh(site_ds)
            chellow.triad.bill(site_ds)

            bill = site_ds.supplier_bill
            for rname, rset in site_ds.supplier_rate_sets.items():
                if len(rset) == 1:
                    bill[rname] = rset.pop()
            values = [site.code, site.name]
            for i in range(1, 4):
                triad_prefix = 'triad-actual-' + str(i)
                values.append(hh_format(bill[triad_prefix + '-date']))
                for suffix in ['-msp-kw', '-laf', '-gsp-kw']:
                    values.append(bill[triad_prefix + suffix])

            values += [
                str(bill['triad-actual-' + suf]) for suf in [
                    'gsp-kw', 'rate', 'gbp']]

            writer.writerow(values)
    except BadRequest as e:
        writer.writerow([e.description])
    except:
        writer.writerow([traceback.format_exc()])
    finally:
        if sess is not None:
            sess.close()
        if f is not None:
            f.close()
            os.rename(running_name, finished_name)
Пример #31
0
def content(year, site_id, sess):
    caches = {}
    try:
        march_finish = datetime.datetime(year, 4, 1, tzinfo=pytz.utc) - HH
        march_start = datetime.datetime(year, 3, 1, tzinfo=pytz.utc)

        yield ', '.join(
            (
                "Site Code", "Site Name", "Displaced TRIAD 1 Date",
                "Displaced TRIAD 1 MSP kW", "Displaced TRIAD LAF",
                "Displaced TRIAD 1 GSP kW", "Displaced TRIAD 2 Date",
                "Displaced TRIAD 2 MSP kW", "Displaced TRIAD 2 LAF",
                "Displaced TRIAD 2 GSP kW", "Displaced TRIAD 3 Date",
                "Displaced TRIAD 3 MSP kW", "Displaced TRIAD 3 LAF",
                "Displaced TRIAD 3 GSP kW", "Displaced GSP kW",
                "Displaced Rate GBP / kW", "GBP")) + '\n'

        forecast_date = chellow.computer.forecast_date()

        if site_id is None:
            sites = sess.query(Site).join(SiteEra).join(Era).join(Supply).join(
                Source).filter(
                Source.code.in_(('gen', 'gen-net')),
                Era.start_date <= march_finish,
                or_(
                    Era.finish_date == null(),
                    Era.finish_date >= march_start)).distinct()
        else:
            site = Site.get_by_id(sess, site_id)
            sites = sess.query(Site).filter(Site.id == site.id)

        for site in sites:
            for site_group in site.groups(
                    sess, march_start, march_finish, True):
                if site_group.start_date > march_start:
                    chunk_start = site_group.start_date
                else:
                    chunk_start = march_start

                if not site_group.finish_date < march_finish:
                    chunk_finish = march_finish
                else:
                    continue

                yield '"' + site.code + '","' + site.name + '"'

                displaced_era = chellow.computer.displaced_era(
                    sess, site_group, chunk_start, chunk_finish)
                if displaced_era is None:
                    continue

                site_ds = chellow.computer.SiteSource(
                    sess, site, chunk_start, chunk_finish, forecast_date, None,
                    caches, displaced_era)
                chellow.duos.duos_vb(site_ds)
                chellow.triad.hh(site_ds)
                chellow.triad.bill(site_ds)

                bill = site_ds.supplier_bill
                for rname, rset in site_ds.supplier_rate_sets.items():
                    if len(rset) == 1:
                        bill[rname] = rset.pop()
                values = []
                for i in range(1, 4):
                    triad_prefix = 'triad-actual-' + str(i)
                    for suffix in ['-date', '-msp-kw', '-laf', '-gsp-kw']:
                        values.append(bill[triad_prefix + suffix])

                values += [
                    bill['triad-actual-' + suf] for suf in [
                        'gsp-kw', 'rate', 'gbp']]

                for value in values:
                    if isinstance(value, datetime.datetime):
                        yield "," + hh_format(value)
                    else:
                        yield "," + str(value)
                yield '\n'
    except:
        yield traceback.format_exc()
Пример #32
0
def _process_sites(sess, file_like, writer, props, report_run):

    ASSET_KEY = "asset_comparison"
    try:
        asset_props = props[ASSET_KEY]
    except KeyError:
        raise BadRequest(
            f"The property {ASSET_KEY} cannot be found in the configuration properties."
        )

    if not isinstance(asset_props, dict):
        raise BadRequest("The {ASSET_KEY} property must be a map.")

    for key in ("ignore_site_codes", ):
        try:
            asset_props[key]
        except KeyError:
            raise BadRequest(
                f"The property {key} cannot be found in the '{ASSET_KEY}' section of "
                f"the configuration properties.")

    ignore_site_codes = asset_props["ignore_site_codes"]

    site_codes_select = (select(Site.code).filter(
        Site.code.notin_(ignore_site_codes)).order_by(Site.code))
    site_codes = [s[0] for s in sess.execute(site_codes_select)]

    titles = (
        "site_code",
        "asset_status",
        "chellow_status",
    )
    writer.writerow(titles)

    parser = iter(csv.reader(file_like))
    next(parser)  # Skip titles

    for values in parser:
        if len(values) == 0:
            continue

        asset_code = values[0].strip()
        asset_status = values[3].strip()

        if asset_code in ignore_site_codes:
            continue

        if asset_code in site_codes:
            site_codes.remove(asset_code)

        eras = sess.execute(
            select(Era).join(SiteEra).join(Site).filter(
                Site.code == asset_code, Era.finish_date == null()).options(
                    joinedload(Era.energisation_status))).all()

        if len(eras) == 0:
            is_energised = None
            is_energised_str = "no supplies"
        else:
            energised_eras = [
                r for r in eras if r[0].energisation_status.code == "E"
            ]
            is_energised = len(energised_eras) > 0
            is_energised_str = "energised" if is_energised is True else "de-energised"

        if asset_status in STATUSES_ACTIVE:
            active_asset = True
        elif asset_status in STATUSES_INACTIVE:
            active_asset = False
        elif asset_status in STATUSES_IGNORE:
            active_asset = None
        else:
            raise BadRequest(f"Asset status '{asset_status}' not recognized.")

        if active_asset is False and is_energised is not None:
            values = {
                "site_code": asset_code,
                "asset_status": asset_status,
                "chellow_status": is_energised_str,
            }
            writer.writerow([values[t] for t in titles])
            site = Site.find_by_code(sess, asset_code)
            values["site_id"] = None if site is None else site.id
            report_run.insert_row(sess, "", titles, values, {})
            sess.commit()

    for site_code in site_codes:
        eras = sess.execute(
            select(Era).join(SiteEra).join(Site).filter(
                Site.code == site_code, Era.finish_date == null()).options(
                    joinedload(Era.energisation_status))).all()

        if len(eras) > 0:
            e_eras = [r for r in eras if r[0].energisation_status.code == "E"]
            is_energised_str = "energised" if len(
                e_eras) > 0 else "de-energised"
            values = {
                "site_code": site_code,
                "asset_status": None,
                "chellow_status": is_energised_str,
            }
            writer.writerow([values[t] for t in titles])
            site = Site.find_by_code(sess, site_code)
            values["site_id"] = None if site is None else site.id
            report_run.insert_row(sess, "", titles, values, {})
            sess.commit()
Пример #33
0
def do_post(sess):

    base_name = []
    now = utc_datetime_now()

    if "scenario_id" in request.values:
        scenario_id = req_int("scenario_id")
        scenario = Scenario.get_by_id(sess, scenario_id)
        scenario_props = scenario.props
        base_name.append(scenario.name)

        start_year = scenario_props["scenario_start_year"]
        start_month = scenario_props["scenario_start_month"]
        start_date_ct = ct_datetime(now.year, now.month, 1)
        if start_year is None:
            scenario_props["scenario_start_year"] = start_date_ct.year
        if start_month is None:
            scenario_props["scenario_start_month"] = start_date_ct.month
    else:
        year = req_int("finish_year")
        month = req_int("finish_month")
        months = req_int("months")
        start_date, _ = next(
            c_months_c(finish_year=year, finish_month=month, months=months))
        by_hh = req_bool("by_hh")
        scenario_props = {
            "scenario_start_year": start_date.year,
            "scenario_start_month": start_date.month,
            "scenario_duration": months,
            "by_hh": by_hh,
        }
        base_name.append("monthly_duration")

    try:
        site_id = req_int("site_id") if "site_id" in request.values else None
        if "site_codes" in request.values:
            site_codes = req_str("site_codes").splitlines()

            # Check sites codes are valid
            for site_code in site_codes:
                Site.get_by_code(sess, site_code)

        else:
            site_codes = []

        if "supply_id" in request.values:
            supply_id = req_int("supply_id")
        else:
            supply_id = None

        if "compression" in request.values:
            compression = req_bool("compression")
        else:
            compression = True
        user = g.user

        args = (
            scenario_props,
            base_name,
            site_id,
            supply_id,
            user,
            compression,
            site_codes,
            now,
        )
        threading.Thread(target=content, args=args).start()
        return chellow_redirect("/downloads", 303)
    except BadRequest as e:
        flash(e.description)
        now = Datetime.utcnow()
        month_start = Datetime(now.year, now.month,
                               1) - relativedelta(months=1)
        month_finish = Datetime(now.year, now.month, 1) - HH
        return make_response(
            render_template(
                "ods_monthly_duration.html",
                month_start=month_start,
                month_finish=month_finish,
            ),
            400,
        )
Пример #34
0
def test_SupplySource_init_nhh(sess, mocker):
    """Old style channels"""
    site = Site.insert(sess, "CI017", "Water Works")
    market_role_Z = MarketRole.insert(sess, "Z", "Non-core")
    participant = Participant.insert(sess, "CALB", "AK Industries")
    participant.insert_party(sess, market_role_Z, "None core",
                             utc_datetime(2000, 1, 1), None, None)
    bank_holiday_rate_script = {"bank_holidays": []}
    Contract.insert_non_core(
        sess,
        "bank_holidays",
        "",
        {},
        utc_datetime(2000, 1, 1),
        None,
        bank_holiday_rate_script,
    )
    market_role_X = MarketRole.insert(sess, "X", "Supplier")
    market_role_M = MarketRole.insert(sess, "M", "Mop")
    market_role_C = MarketRole.insert(sess, "C", "HH Dc")
    market_role_R = MarketRole.insert(sess, "R", "Distributor")
    participant.insert_party(sess, market_role_M, "Fusion Mop Ltd",
                             utc_datetime(2000, 1, 1), None, None)
    participant.insert_party(sess, market_role_X, "Fusion Ltc",
                             utc_datetime(2000, 1, 1), None, None)
    participant.insert_party(sess, market_role_C, "Fusion DC",
                             utc_datetime(2000, 1, 1), None, None)
    mop_contract = Contract.insert_mop(sess, "Fusion", participant, "", {},
                                       utc_datetime(2000, 1, 1), None, {})
    dc_contract = Contract.insert_hhdc(sess, "Fusion DC 2000", participant, "",
                                       {}, utc_datetime(2000, 1, 1), None, {})
    pc = Pc.insert(sess, "03", "nhh", utc_datetime(2000, 1, 1), None)
    ssc = Ssc.insert(sess, "0393", "unrestricted", True, utc_datetime(2000, 1),
                     None)
    insert_cops(sess)
    cop = Cop.get_by_code(sess, "5")
    exp_supplier_contract = Contract.insert_supplier(
        sess,
        "Fusion Supplier 2000",
        participant,
        "",
        {},
        utc_datetime(2000, 1, 1),
        None,
        {},
    )
    dno = participant.insert_party(sess, market_role_R, "WPD",
                                   utc_datetime(2000, 1, 1), None, "22")
    meter_type = MeterType.insert(sess, "C5", "COP 1-5",
                                  utc_datetime(2000, 1, 1), None)
    meter_payment_type = MeterPaymentType.insert(sess, "CR", "Credit",
                                                 utc_datetime(1996, 1, 1),
                                                 None)
    Mtc.insert(
        sess,
        None,
        "845",
        "HH COP5 And Above With Comms",
        False,
        False,
        True,
        meter_type,
        meter_payment_type,
        0,
        utc_datetime(1996, 1, 1),
        None,
    )
    insert_voltage_levels(sess)
    voltage_level = VoltageLevel.get_by_code(sess, "HV")
    dno.insert_llfc(
        sess,
        "510",
        "PC 5-8 & HH HV",
        voltage_level,
        False,
        True,
        utc_datetime(1996, 1, 1),
        None,
    )
    dno.insert_llfc(
        sess,
        "521",
        "Export (HV)",
        voltage_level,
        False,
        False,
        utc_datetime(1996, 1, 1),
        None,
    )
    insert_sources(sess)
    source = Source.get_by_code(sess, "net")
    insert_energisation_statuses(sess)
    energisation_status = EnergisationStatus.get_by_code(sess, "D")
    gsp_group = GspGroup.insert(sess, "_L", "South Western")
    supply = site.insert_e_supply(
        sess,
        source,
        None,
        "Bob",
        utc_datetime(2000, 1, 1),
        None,
        gsp_group,
        mop_contract,
        "773",
        dc_contract,
        "ghyy3",
        "hgjeyhuw",
        pc,
        "845",
        cop,
        ssc,
        energisation_status,
        {},
        None,
        None,
        None,
        None,
        None,
        "22 7867 6232 781",
        "521",
        exp_supplier_contract,
        "7748",
        361,
    )
    era = supply.eras[0]
    active_channel = era.insert_channel(sess, False, "ACTIVE")
    active_data_raw = [{
        "start_date": utc_datetime(2009, 8, 10),
        "value": 10,
        "status": "A",
    }]
    active_channel.add_hh_data(sess, active_data_raw)
    era.insert_channel(sess, True, "REACTIVE_IMP")

    sess.commit()

    caches = {}
    start_date = utc_datetime(2009, 7, 31, 23, 00)
    finish_date = utc_datetime(2009, 8, 31, 22, 30)
    forecast_date = utc_datetime(2019, 8, 31, 22, 30)
    is_import = False
    chellow.computer.SupplySource(sess, start_date, finish_date, forecast_date,
                                  era, is_import, caches)
Пример #35
0
def content(scenario_props, scenario_id, base_name, site_id, supply_id, user,
            compression):
    now = utc_datetime_now()
    report_context = {}

    try:
        comp = report_context['computer']
    except KeyError:
        comp = report_context['computer'] = {}

    try:
        rate_cache = comp['rates']
    except KeyError:
        rate_cache = comp['rates'] = {}

    try:
        ind_cont = report_context['contract_names']
    except KeyError:
        ind_cont = report_context['contract_names'] = {}

    sess = None
    try:
        sess = Session()
        if scenario_props is None:
            scenario_contract = Contract.get_supplier_by_id(sess, scenario_id)
            scenario_props = scenario_contract.make_properties()
            base_name.append(scenario_contract.name)

        start_date = scenario_props['scenario_start']
        if start_date is None:
            start_date = utc_datetime(now.year, now.month, 1)
        else:
            start_date = to_utc(start_date)

        base_name.append(
            hh_format(start_date).replace(' ',
                                          '_').replace(':',
                                                       '').replace('-', ''))

        months = scenario_props['scenario_duration']
        base_name.append('for')
        base_name.append(str(months))
        base_name.append('months')
        finish_date = start_date + relativedelta(months=months)

        if 'forecast_from' in scenario_props:
            forecast_from = scenario_props['forecast_from']
        else:
            forecast_from = None

        if forecast_from is None:
            forecast_from = chellow.computer.forecast_date()
        else:
            forecast_from = to_utc(forecast_from)

        sites = sess.query(Site).distinct().order_by(Site.code)
        if site_id is not None:
            site = Site.get_by_id(sess, site_id)
            sites = sites.filter(Site.id == site.id)
            base_name.append('site')
            base_name.append(site.code)
        if supply_id is not None:
            supply = Supply.get_by_id(sess, supply_id)
            base_name.append('supply')
            base_name.append(str(supply.id))
            sites = sites.join(SiteEra).join(Era).filter(Era.supply == supply)

        running_name, finished_name = chellow.dloads.make_names(
            '_'.join(base_name) + '.ods', user)

        rf = open(running_name, "wb")
        site_rows = []
        era_rows = []

        for rate_script in get_map_list(scenario_props, 'local_rates'):
            contract_id = rate_script['contract_id']
            try:
                cont_cache = rate_cache[contract_id]
            except KeyError:
                cont_cache = rate_cache[contract_id] = {}

            try:
                rate_script_start = rate_script['start_date']
            except KeyError:
                raise BadRequest(
                    "Problem in the scenario properties. Can't find the " +
                    "'start_date' key of the contract " + str(contract_id) +
                    " in the 'local_rates' map.")

            try:
                rate_script_start = rate_script['start_date']
            except KeyError:
                raise BadRequest(
                    "Problem in the scenario properties. Can't find the " +
                    "'start_date' key of the contract " + str(contract_id) +
                    " in the 'local_rates' map.")

            for dt in hh_range(report_context, rate_script_start,
                               rate_script['finish_date']):
                cont_cache[dt] = PropDict('scenario properties',
                                          rate_script['script'])

        for rate_script in get_map_list(scenario_props, 'industry_rates'):
            contract_name = rate_script['contract_name']
            try:
                cont_cache = ind_cont[contract_name]
            except KeyError:
                cont_cache = ind_cont[contract_name] = {}

            rfinish = rate_script['finish_date']
            if rfinish is None:
                raise BadRequest("For the industry rate " + contract_name +
                                 " the "
                                 "finish_date can't be null.")
            for dt in hh_range(report_context, rate_script['start_date'],
                               rfinish):
                cont_cache[dt] = PropDict('scenario properties',
                                          rate_script['script'])

        era_maps = scenario_props.get('era_maps', {})

        scenario_hh = scenario_props.get('hh_data', {})

        era_header_titles = [
            'creation-date', 'imp-mpan-core', 'imp-supplier-contract',
            'exp-mpan-core', 'exp-supplier-contract', 'metering-type',
            'source', 'generator-type', 'supply-name', 'msn', 'pc', 'site-id',
            'site-name', 'associated-site-ids', 'month'
        ]
        site_header_titles = [
            'creation-date', 'site-id', 'site-name', 'associated-site-ids',
            'month', 'metering-type', 'sources', 'generator-types'
        ]
        summary_titles = [
            'import-net-kwh', 'export-net-kwh', 'import-gen-kwh',
            'export-gen-kwh', 'import-3rd-party-kwh', 'export-3rd-party-kwh',
            'displaced-kwh', 'used-kwh', 'used-3rd-party-kwh',
            'import-net-gbp', 'export-net-gbp', 'import-gen-gbp',
            'export-gen-gbp', 'import-3rd-party-gbp', 'export-3rd-party-gbp',
            'displaced-gbp', 'used-gbp', 'used-3rd-party-gbp',
            'billed-import-net-kwh', 'billed-import-net-gbp'
        ]

        title_dict = {}
        for cont_type, con_attr in (('mop', Era.mop_contract),
                                    ('dc', Era.dc_contract),
                                    ('imp-supplier',
                                     Era.imp_supplier_contract),
                                    ('exp-supplier',
                                     Era.exp_supplier_contract)):
            titles = []
            title_dict[cont_type] = titles
            conts = sess.query(Contract).join(con_attr).join(Era.supply). \
                join(Source).filter(
                    Era.start_date <= finish_date, or_(
                        Era.finish_date == null(),
                        Era.finish_date >= start_date),
                    Source.code.in_(('net', '3rd-party'))
                ).distinct().order_by(Contract.id)
            if supply_id is not None:
                conts = conts.filter(Era.supply_id == supply_id)
            for cont in conts:
                title_func = chellow.computer.contract_func(
                    report_context, cont, 'virtual_bill_titles')
                if title_func is None:
                    raise Exception("For the contract " + cont.name +
                                    " there doesn't seem to be a "
                                    "'virtual_bill_titles' function.")
                for title in title_func():
                    if title not in titles:
                        titles.append(title)

        tpr_query = sess.query(Tpr).join(MeasurementRequirement).join(Ssc). \
            join(Era).filter(
                Era.start_date <= finish_date, or_(
                    Era.finish_date == null(),
                    Era.finish_date >= start_date)
            ).order_by(Tpr.code).distinct()
        for tpr in tpr_query.filter(Era.imp_supplier_contract != null()):
            for suffix in ('-kwh', '-rate', '-gbp'):
                title_dict['imp-supplier'].append(tpr.code + suffix)
        for tpr in tpr_query.filter(Era.exp_supplier_contract != null()):
            for suffix in ('-kwh', '-rate', '-gbp'):
                title_dict['exp-supplier'].append(tpr.code + suffix)

        era_rows.append(
            era_header_titles + summary_titles + [None] +
            ['mop-' + t for t in title_dict['mop']] + [None] +
            ['dc-' + t for t in title_dict['dc']] + [None] +
            ['imp-supplier-' + t for t in title_dict['imp-supplier']] +
            [None] + ['exp-supplier-' + t for t in title_dict['exp-supplier']])
        site_rows.append(site_header_titles + summary_titles)

        sites = sites.all()
        deltas = {}
        for site in sites:
            try:
                site_scenario_hh = scenario_hh[site.code]
            except KeyError:
                site_scenario_hh = scenario_hh[site.code] = {}

            site_deltas = deltas[site.code] = {'hhs': {}}
            delts = site_deltas['supply_deltas'] = {}
            for is_import in (True, False):
                delts[is_import] = {}
                for src in ('gen', 'net', 'gen-net', '3rd-party',
                            '3rd-party-reverse', 'sub'):
                    delts[is_import][src] = {'site': {}}

            earliest_delta = to_utc(Datetime.max)
            latest_delta = to_utc(Datetime.min)

            found_hh = False
            for typ in ('used', 'generated', 'parasitic', 'gen_net'):
                hh_str = site_scenario_hh.get(typ, '')
                hh_data = site_scenario_hh[typ] = {}
                for row in csv.reader(StringIO(hh_str)):
                    cells = [cell.strip() for cell in row]
                    if len(''.join(cells)) == 0:
                        continue

                    if len(cells) != 2:
                        raise BadRequest(
                            "Can't interpret the row " + str(cells) +
                            " it should be of the form 'timestamp, kWh'")

                    date_str, kw_str = cells
                    ts = parse_hh_start(date_str)
                    earliest_delta = min(ts, earliest_delta)
                    latest_delta = max(ts, latest_delta)
                    hh_data[ts] = float(kw_str)
                    found_hh = True

            if not found_hh:
                continue

            scenario_used = site_scenario_hh['used']
            scenario_generated = site_scenario_hh['generated']
            scenario_parasitic = site_scenario_hh['parasitic']
            scenario_gen_net = site_scenario_hh['gen_net']

            month_start = utc_datetime(earliest_delta.year,
                                       earliest_delta.month)
            while month_start <= latest_delta:
                month_finish = month_start + relativedelta(months=1) - HH
                chunk_start = hh_max(month_start, earliest_delta)
                chunk_finish = hh_min(month_finish, latest_delta)
                site_ds = chellow.computer.SiteSource(sess, site, chunk_start,
                                                      chunk_finish,
                                                      forecast_from,
                                                      report_context)
                hh_map = dict((h['start-date'], h) for h in site_ds.hh_data)

                for era in sess.query(Era).join(SiteEra).join(Pc).filter(
                        SiteEra.site == site, SiteEra.is_physical == true(),
                        Era.imp_mpan_core != null(), Pc.code != '00',
                        Era.start_date <= chunk_finish,
                        or_(Era.finish_date == null(),
                            Era.finish_date >= chunk_start),
                        ~Era.channels.any()):

                    if supply_id is not None and era.supply_id != supply_id:
                        continue

                    ss_start = hh_max(era.start_date, chunk_start)
                    ss_finish = hh_min(era.finish_date, chunk_finish)

                    ss = SupplySource(sess, ss_start, ss_finish, forecast_from,
                                      era, True, report_context)

                    for hh in ss.hh_data:
                        sdatum = hh_map[hh['start-date']]
                        sdatum['import-net-kwh'] += hh['msp-kwh']
                        sdatum['used-kwh'] += hh['msp-kwh']

                for era in sess.query(Era).join(SiteEra).join(Pc).join(
                        Supply).join(Source).filter(
                            SiteEra.site == site,
                            SiteEra.is_physical == true(),
                            Era.imp_mpan_core != null(),
                            Era.start_date <= chunk_finish,
                            or_(Era.finish_date == null(),
                                Era.finish_date >= chunk_start),
                            Source.code == 'gen-net'):

                    if supply_id is not None and era.supply_id != supply_id:
                        continue

                    ss_start = hh_max(era.start_date, chunk_start)
                    ss_finish = hh_min(era.finish_date, chunk_finish)

                    ss = SupplySource(sess, ss_start, ss_finish, forecast_from,
                                      era, False, report_context)

                    for hh in ss.hh_data:
                        sdatum = hh_map[hh['start-date']]
                        try:
                            sdatum['gen-net-kwh'] += hh['msp-kwh']
                        except KeyError:
                            sdatum['gen-net-kwh'] = hh['msp-kwh']

                for hh in site_ds.hh_data:
                    hh_start = hh['start-date']
                    if hh_start in scenario_used:
                        used_delt = scenario_used[hh_start] - hh['used-kwh']
                        imp_net_delt = 0
                        exp_net_delt = 0

                        if used_delt < 0:
                            diff = hh['import-net-kwh'] + used_delt
                            if diff < 0:
                                imp_net_delt -= hh['import-net-kwh']
                                exp_net_delt -= diff
                            else:
                                imp_net_delt += used_delt
                        else:
                            diff = hh['export-net-kwh'] - used_delt
                            if diff < 0:
                                exp_net_delt -= hh['export-net-kwh']
                                imp_net_delt -= diff
                            else:
                                exp_net_delt -= used_delt

                        try:
                            delts[False]['net']['site'][hh_start] += \
                                exp_net_delt
                        except KeyError:
                            delts[False]['net']['site'][hh_start] = \
                                exp_net_delt

                        try:
                            delts[True]['net']['site'][hh_start] += \
                                imp_net_delt
                        except KeyError:
                            delts[True]['net']['site'][hh_start] = imp_net_delt

                        hh['import-net-kwh'] += imp_net_delt
                        hh['export-net-kwh'] += exp_net_delt
                        hh['used-kwh'] += used_delt
                        hh['msp-kwh'] -= exp_net_delt

                    if hh_start in scenario_generated:
                        imp_gen_delt = scenario_generated[hh_start] - \
                            hh['import-gen-kwh']
                        imp_net_delt = 0
                        exp_net_delt = 0

                        if imp_gen_delt < 0:
                            diff = hh['export-net-kwh'] + imp_gen_delt
                            if diff < 0:
                                exp_net_delt -= hh['export-net-kwh']
                                imp_net_delt -= diff
                            else:
                                exp_net_delt += imp_gen_delt
                        else:
                            diff = hh['import-net-kwh'] - imp_gen_delt
                            if diff < 0:
                                imp_net_delt -= hh['import-net-kwh']
                                exp_net_delt -= diff
                            else:
                                imp_net_delt -= imp_gen_delt

                        try:
                            delts[True]['gen']['site'][hh_start] += \
                                imp_gen_delt
                        except KeyError:
                            delts[True]['gen']['site'][hh_start] = imp_gen_delt

                        try:
                            delts[False]['net']['site'][hh_start] += \
                                exp_net_delt
                        except KeyError:
                            delts[False]['net']['site'][hh_start] = \
                                exp_net_delt

                        try:
                            delts[True]['net']['site'][hh_start] += \
                                imp_net_delt
                        except KeyError:
                            delts[True]['net']['site'][hh_start] = imp_net_delt

                        hh['import-net-kwh'] += imp_net_delt
                        hh['export-net-kwh'] += exp_net_delt
                        hh['import-gen-kwh'] += imp_gen_delt
                        hh['msp-kwh'] -= imp_net_delt

                    if hh_start in scenario_parasitic:
                        exp_gen_delt = scenario_parasitic[hh_start] - \
                            hh['export-gen-kwh']
                        imp_net_delt = 0
                        exp_net_delt = 0

                        if exp_gen_delt < 0:
                            diff = hh['import-net-kwh'] + exp_gen_delt
                            if diff < 0:
                                imp_net_delt -= hh['import-net-kwh']
                                exp_net_delt -= diff
                            else:
                                imp_net_delt += exp_gen_delt
                        else:
                            diff = hh['export-net-kwh'] - exp_gen_delt
                            if diff < 0:
                                exp_net_delt -= hh['export-net-kwh']
                                imp_net_delt -= diff
                            else:
                                exp_net_delt -= exp_gen_delt

                        try:
                            delts[False]['gen']['site'][hh_start] += \
                                imp_gen_delt
                        except KeyError:
                            delts[False]['gen']['site'][hh_start] = \
                                exp_gen_delt

                        try:
                            delts[False]['net']['site'][hh_start] += \
                                exp_net_delt
                        except KeyError:
                            delts[False]['net']['site'][hh_start] = \
                                exp_net_delt

                        try:
                            delts[True]['net']['site'][hh_start] += \
                                imp_net_delt
                        except KeyError:
                            delts[True]['net']['site'][hh_start] = imp_net_delt

                        hh['import-net-kwh'] += imp_net_delt
                        hh['export-net-kwh'] += exp_net_delt
                        hh['export-gen-kwh'] += exp_gen_delt
                        hh['msp-kwh'] -= imp_net_delt

                    if hh_start in scenario_gen_net:
                        gen_net_delt = scenario_gen_net[hh_start] - \
                            hh['gen-net-kwh']

                        try:
                            delts[False]['gen-net']['site'][hh_start] += \
                                gen_net_delt
                        except KeyError:
                            delts[False]['gen-net']['site'][hh_start] = \
                                gen_net_delt

                        hh['import-gen-kwh'] += gen_net_delt
                        hh['export-net-kwh'] += gen_net_delt

                    site_deltas['hhs'][hh_start] = hh
                month_start += relativedelta(months=1)

        month_start = start_date
        while month_start < finish_date:
            month_finish = month_start + relativedelta(months=1) - HH
            for site in sites:
                site_category = None
                site_sources = set()
                site_gen_types = set()
                site_month_data = defaultdict(int)
                calcs = []
                for era in sess.query(Era).join(SiteEra).join(Pc).filter(
                        SiteEra.site == site, SiteEra.is_physical == true(),
                        Era.start_date <= month_finish,
                        or_(Era.finish_date == null(),
                            Era.finish_date >= month_start)).options(
                                joinedload(Era.ssc),
                                joinedload(Era.dc_contract),
                                joinedload(Era.mop_contract),
                                joinedload(Era.imp_supplier_contract),
                                joinedload(Era.exp_supplier_contract),
                                joinedload(Era.channels),
                                joinedload(Era.imp_llfc).joinedload(
                                    Llfc.voltage_level),
                                joinedload(Era.exp_llfc).joinedload(
                                    Llfc.voltage_level), joinedload(Era.cop),
                                joinedload(Era.supply).joinedload(Supply.dno),
                                joinedload(Era.supply).joinedload(
                                    Supply.gsp_group),
                                joinedload(Era.supply).joinedload(
                                    Supply.source),
                                joinedload(Era.mtc).joinedload(Mtc.meter_type),
                                joinedload(Era.pc),
                                joinedload(Era.site_eras)).order_by(Pc.code):

                    supply = era.supply
                    if supply.generator_type is not None:
                        site_gen_types.add(supply.generator_type.code)

                    if supply_id is not None and supply.id != supply_id:
                        continue

                    ss_start = hh_max(era.start_date, month_start)
                    ss_finish = hh_min(era.finish_date, month_finish)

                    if era.imp_mpan_core is None:
                        imp_ss = None
                    else:
                        sup_deltas = site_deltas['supply_deltas'][True][
                            supply.source.code]

                        imp_ss = SupplySource(sess,
                                              ss_start,
                                              ss_finish,
                                              forecast_from,
                                              era,
                                              True,
                                              report_context,
                                              era_maps=era_maps,
                                              deltas=sup_deltas)

                    if era.exp_mpan_core is None:
                        exp_ss = None
                        measurement_type = imp_ss.measurement_type
                    else:
                        sup_deltas = site_deltas['supply_deltas'][False][
                            supply.source.code]

                        exp_ss = SupplySource(sess,
                                              ss_start,
                                              ss_finish,
                                              forecast_from,
                                              era,
                                              False,
                                              report_context,
                                              era_maps=era_maps,
                                              deltas=sup_deltas)
                        measurement_type = exp_ss.measurement_type

                    order = meter_order[measurement_type]
                    calcs.append((order, era.imp_mpan_core, era.exp_mpan_core,
                                  imp_ss, exp_ss))

                # Check if gen deltas haven't been consumed
                extra_sss = set()
                for is_imp in (True, False):
                    sup_deltas = site_deltas['supply_deltas'][is_imp]['gen']
                    if len(
                            list(t for t in sup_deltas['site']
                                 if month_start <= t <= month_finish)) > 0:
                        extra_sss.add(is_imp)

                displaced_era = chellow.computer.displaced_era(
                    sess,
                    report_context,
                    site,
                    month_start,
                    month_finish,
                    forecast_from,
                    has_scenario_generation=len(extra_sss) > 0)

                if len(extra_sss) > 0:
                    if True in extra_sss:
                        sup_deltas = site_deltas['supply_deltas'][True]['gen']
                        imp_ss_name = site.code + "_extra_gen_TRUE"
                        imp_ss = ScenarioSource(
                            sess, month_start, month_finish, True,
                            report_context, sup_deltas,
                            displaced_era.imp_supplier_contract, imp_ss_name)
                    else:
                        imp_ss_name = imp_ss = None
                    if False in extra_sss:
                        exp_ss_name = site.code + "_extra_gen_FALSE"
                        sup_deltas = site_deltas['supply_deltas'][False]['gen']
                        exp_ss = ScenarioSource(
                            sess, month_start, month_finish, False,
                            report_context, sup_deltas,
                            displaced_era.imp_supplier_contract, imp_ss_name)
                    else:
                        exp_ss_name = exp_ss = None

                    calcs.append((0, imp_ss_name, exp_ss_name, imp_ss, exp_ss))

                # Check if exp net deltas haven't been consumed
                sup_deltas = site_deltas['supply_deltas'][False]['net']
                if len(
                        list(t for t in sup_deltas['site']
                             if month_start <= t <= month_finish)) > 0:
                    ss_name = site.code + "_extra_net_export"
                    ss = SupplySource(sess,
                                      month_start,
                                      month_finish,
                                      forecast_from,
                                      displaced_era,
                                      False,
                                      report_context,
                                      era_maps=era_maps,
                                      deltas=sup_deltas)

                    calcs.append((0, None, ss_name, None, ss))

                site_ds = chellow.computer.SiteSource(sess,
                                                      site,
                                                      month_start,
                                                      month_finish,
                                                      forecast_from,
                                                      report_context,
                                                      displaced_era,
                                                      deltas=site_deltas)

                if displaced_era is not None and supply_id is None:
                    month_data = {}
                    for sname in ('import-net', 'export-net', 'import-gen',
                                  'export-gen', 'import-3rd-party',
                                  'export-3rd-party', 'msp', 'used',
                                  'used-3rd-party', 'billed-import-net'):
                        for xname in ('kwh', 'gbp'):
                            month_data[sname + '-' + xname] = 0

                    month_data['used-kwh'] = month_data['displaced-kwh'] = sum(
                        hh['msp-kwh'] for hh in site_ds.hh_data)

                    disp_supplier_contract = \
                        displaced_era.imp_supplier_contract
                    disp_vb_function = chellow.computer.contract_func(
                        report_context, disp_supplier_contract,
                        'displaced_virtual_bill')
                    if disp_vb_function is None:
                        raise BadRequest(
                            "The supplier contract " +
                            disp_supplier_contract.name +
                            " doesn't have the displaced_virtual_bill() "
                            "function.")
                    disp_vb_function(site_ds)
                    disp_supplier_bill = site_ds.supplier_bill

                    try:
                        gbp = disp_supplier_bill['net-gbp']
                    except KeyError:
                        disp_supplier_bill['problem'] += 'For the supply ' + \
                            site_ds.mpan_core + ' the virtual bill ' + \
                            str(disp_supplier_bill) + ' from the contract ' + \
                            disp_supplier_contract.name + \
                            ' does not contain the net-gbp key.'

                    month_data['used-gbp'] = month_data['displaced-gbp'] = \
                        site_ds.supplier_bill['net-gbp']

                    out = [
                        now, None, disp_supplier_contract.name, None, None,
                        displaced_era.meter_category, 'displaced', None, None,
                        None, None, site.code, site.name, '', month_finish
                    ] + [month_data[t] for t in summary_titles
                         ] + [None] + [None] * len(title_dict['mop']) + [
                             None
                         ] + [None] * len(title_dict['dc']) + [
                             None
                         ] + make_bill_row(title_dict['imp-supplier'],
                                           disp_supplier_bill)

                    era_rows.append(out)
                    for k, v in month_data.items():
                        site_month_data[k] += v

                for i, (order, imp_mpan_core, exp_mpan_core, imp_ss,
                        exp_ss) in enumerate(sorted(calcs, key=str)):
                    if imp_ss is None:
                        source_code = exp_ss.source_code
                        supply = exp_ss.supply
                    else:
                        source_code = imp_ss.source_code
                        supply = imp_ss.supply

                    site_sources.add(source_code)
                    month_data = {}
                    for name in ('import-net', 'export-net', 'import-gen',
                                 'export-gen', 'import-3rd-party',
                                 'export-3rd-party', 'displaced', 'used',
                                 'used-3rd-party', 'billed-import-net'):
                        for sname in ('kwh', 'gbp'):
                            month_data[name + '-' + sname] = 0

                    if imp_ss is not None:
                        imp_supplier_contract = imp_ss.supplier_contract
                        if imp_supplier_contract is not None:
                            import_vb_function = contract_func(
                                report_context, imp_supplier_contract,
                                'virtual_bill')
                            if import_vb_function is None:
                                raise BadRequest(
                                    "The supplier contract " +
                                    imp_supplier_contract.name +
                                    " doesn't have the virtual_bill() "
                                    "function.")
                            import_vb_function(imp_ss)

                        kwh = sum(hh['msp-kwh'] for hh in imp_ss.hh_data)
                        imp_supplier_bill = imp_ss.supplier_bill

                        try:
                            gbp = imp_supplier_bill['net-gbp']
                        except KeyError:
                            gbp = 0
                            imp_supplier_bill['problem'] += \
                                'For the supply ' + \
                                imp_ss.mpan_core + \
                                ' the virtual bill ' + \
                                str(imp_supplier_bill) + \
                                ' from the contract ' + \
                                imp_supplier_contract.name + \
                                ' does not contain the net-gbp key.'

                        if source_code in ('net', 'gen-net'):
                            month_data['import-net-gbp'] += gbp
                            month_data['import-net-kwh'] += kwh
                            month_data['used-gbp'] += gbp
                            month_data['used-kwh'] += kwh
                            if source_code == 'gen-net':
                                month_data['export-gen-kwh'] += kwh
                        elif source_code == '3rd-party':
                            month_data['import-3rd-party-gbp'] += gbp
                            month_data['import-3rd-party-kwh'] += kwh
                            month_data['used-3rd-party-gbp'] += gbp
                            month_data['used-3rd-party-kwh'] += kwh
                            month_data['used-gbp'] += gbp
                            month_data['used-kwh'] += kwh
                        elif source_code == '3rd-party-reverse':
                            month_data['export-3rd-party-gbp'] += gbp
                            month_data['export-3rd-party-kwh'] += kwh
                            month_data['used-3rd-party-gbp'] -= gbp
                            month_data['used-3rd-party-kwh'] -= kwh
                            month_data['used-gbp'] -= gbp
                            month_data['used-kwh'] -= kwh
                        elif source_code == 'gen':
                            month_data['import-gen-kwh'] += kwh

                    if exp_ss is not None:
                        exp_supplier_contract = exp_ss.supplier_contract
                        if exp_supplier_contract is not None:
                            export_vb_function = contract_func(
                                report_context, exp_supplier_contract,
                                'virtual_bill')
                            export_vb_function(exp_ss)

                        kwh = sum(hh['msp-kwh'] for hh in exp_ss.hh_data)
                        exp_supplier_bill = exp_ss.supplier_bill
                        try:
                            gbp = exp_supplier_bill['net-gbp']
                        except KeyError:
                            exp_supplier_bill['problem'] += \
                                'For the supply ' + imp_ss.mpan_core + \
                                ' the virtual bill ' + \
                                str(imp_supplier_bill) + \
                                ' from the contract ' + \
                                imp_supplier_contract.name + \
                                ' does not contain the net-gbp key.'

                        if source_code in ('net', 'gen-net'):
                            month_data['export-net-gbp'] += gbp
                            month_data['export-net-kwh'] += kwh
                            if source_code == 'gen-net':
                                month_data['import-gen-kwh'] += kwh

                        elif source_code == '3rd-party':
                            month_data['export-3rd-party-gbp'] += gbp
                            month_data['export-3rd-party-kwh'] += kwh
                            month_data['used-3rd-party-gbp'] -= gbp
                            month_data['used-3rd-party-kwh'] -= kwh
                            month_data['used-gbp'] -= gbp
                            month_data['used-kwh'] -= kwh
                        elif source_code == '3rd-party-reverse':
                            month_data['import-3rd-party-gbp'] += gbp
                            month_data['import-3rd-party-kwh'] += kwh
                            month_data['used-3rd-party-gbp'] += gbp
                            month_data['used-3rd-party-kwh'] += kwh
                            month_data['used-gbp'] += gbp
                            month_data['used-kwh'] += kwh
                        elif source_code == 'gen':
                            month_data['export-gen-kwh'] += kwh

                    sss = exp_ss if imp_ss is None else imp_ss
                    dc_contract = sss.dc_contract
                    if dc_contract is not None:
                        sss.contract_func(dc_contract, 'virtual_bill')(sss)
                    dc_bill = sss.dc_bill
                    gbp = dc_bill['net-gbp']

                    mop_contract = sss.mop_contract
                    if mop_contract is not None:
                        mop_bill_function = sss.contract_func(
                            mop_contract, 'virtual_bill')
                        mop_bill_function(sss)
                    mop_bill = sss.mop_bill
                    gbp += mop_bill['net-gbp']

                    if source_code in ('3rd-party', '3rd-party-reverse'):
                        month_data['import-3rd-party-gbp'] += gbp
                        month_data['used-3rd-party-gbp'] += gbp
                    else:
                        month_data['import-net-gbp'] += gbp
                    month_data['used-gbp'] += gbp

                    generator_type = sss.generator_type_code
                    if source_code in ('gen', 'gen-net'):
                        site_gen_types.add(generator_type)

                    era_category = sss.measurement_type
                    if CATEGORY_ORDER[site_category] < \
                            CATEGORY_ORDER[era_category]:
                        site_category = era_category

                    era_associates = set()
                    if mop_contract is not None:
                        era_associates.update({
                            s.site.code
                            for s in era.site_eras if not s.is_physical
                        })

                        for bill in sess.query(Bill).filter(
                                Bill.supply == supply,
                                Bill.start_date <= sss.finish_date,
                                Bill.finish_date >= sss.start_date):
                            bill_start = bill.start_date
                            bill_finish = bill.finish_date
                            bill_duration = (
                                bill_finish - bill_start).total_seconds() + \
                                (30 * 60)
                            overlap_duration = (
                                min(bill_finish, sss.finish_date) -
                                max(bill_start, sss.start_date)
                            ).total_seconds() + (30 * 60)
                            overlap_proportion = overlap_duration / \
                                bill_duration
                            month_data['billed-import-net-kwh'] += \
                                overlap_proportion * float(bill.kwh)
                            month_data['billed-import-net-gbp'] += \
                                overlap_proportion * float(bill.net)

                    if imp_ss is None:
                        imp_supplier_contract_name = None
                        pc_code = exp_ss.pc_code
                    else:
                        if imp_supplier_contract is None:
                            imp_supplier_contract_name = ''
                        else:
                            imp_supplier_contract_name = \
                                imp_supplier_contract.name
                        pc_code = imp_ss.pc_code

                    if exp_ss is None:
                        exp_supplier_contract_name = None
                    else:
                        if exp_supplier_contract is None:
                            exp_supplier_contract_name = ''
                        else:
                            exp_supplier_contract_name = \
                                exp_supplier_contract.name

                    out = [
                        now, imp_mpan_core, imp_supplier_contract_name,
                        exp_mpan_core, exp_supplier_contract_name,
                        era_category, source_code, generator_type,
                        sss.supply_name, sss.msn, pc_code, site.code,
                        site.name, ','.join(sorted(list(era_associates))),
                        month_finish] + [
                        month_data[t] for t in summary_titles] + [None] + \
                        make_bill_row(title_dict['mop'], mop_bill) + [None] + \
                        make_bill_row(title_dict['dc'], dc_bill)
                    if imp_ss is None:
                        out += [None] * (len(title_dict['imp-supplier']) + 1)
                    else:
                        out += [None] + make_bill_row(
                            title_dict['imp-supplier'], imp_supplier_bill)
                    if exp_ss is not None:
                        out += [None] + make_bill_row(
                            title_dict['exp-supplier'], exp_supplier_bill)

                    for k, v in month_data.items():
                        site_month_data[k] += v
                    era_rows.append(out)

                site_rows.append([
                    now, site.code, site.name, ', '.join(
                        s.code for s in site.find_linked_sites(
                            sess, month_start, month_finish)), month_finish,
                    site_category, ', '.join(sorted(list(site_sources))),
                    ', '.join(sorted(list(site_gen_types)))
                ] + [site_month_data[k] for k in summary_titles])
                sess.rollback()
            write_spreadsheet(rf, compression, site_rows, era_rows)
            month_start += relativedelta(months=1)
    except BadRequest as e:
        msg = e.description + traceback.format_exc()
        sys.stderr.write(msg + '\n')
        site_rows.append(["Problem " + msg])
        write_spreadsheet(rf, compression, site_rows, era_rows)
    except BaseException:
        msg = traceback.format_exc()
        sys.stderr.write(msg + '\n')
        site_rows.append(["Problem " + msg])
        write_spreadsheet(rf, compression, site_rows, era_rows)
    finally:
        if sess is not None:
            sess.close()
        try:
            rf.close()
            os.rename(running_name, finished_name)
        except BaseException:
            msg = traceback.format_exc()
            r_name, f_name = chellow.dloads.make_names('error.txt', user)
            ef = open(r_name, "w")
            ef.write(msg + '\n')
            ef.close()