Exemple #1
0
def test_make_val():
    v = {0, "hello"}
    make_val(v)
def content(start_date, finish_date, g_contract_id, user):
    report_context = {}
    sess = None
    try:
        sess = Session()
        running_name, finished_name = chellow.dloads.make_names(
            "gas_virtual_bills.csv", user
        )
        f = open(running_name, mode="w", newline="")
        writer = csv.writer(f, lineterminator="\n")

        g_contract = GContract.get_by_id(sess, g_contract_id)
        forecast_dt = forecast_date()

        month_start = utc_datetime(start_date.year, start_date.month, 1)
        month_finish = month_start + relativedelta(months=1) - HH

        bill_titles = contract_func(report_context, g_contract, "virtual_bill_titles")()
        writer.writerow(
            ["MPRN", "Site Code", "Site Name", "Account", "From", "To"] + bill_titles
        )

        while not month_start > finish_date:
            period_start = hh_max(start_date, month_start)
            period_finish = hh_min(finish_date, month_finish)

            for g_era in (
                sess.query(GEra)
                .distinct()
                .filter(
                    GEra.g_contract == g_contract,
                    GEra.start_date <= period_finish,
                    or_(GEra.finish_date == null(), GEra.finish_date >= period_start),
                )
            ):

                chunk_start = hh_max(g_era.start_date, period_start)
                chunk_finish = hh_min(g_era.finish_date, period_finish)

                data_source = GDataSource(
                    sess,
                    chunk_start,
                    chunk_finish,
                    forecast_dt,
                    g_era,
                    report_context,
                    None,
                )

                site = (
                    sess.query(Site)
                    .join(SiteGEra)
                    .filter(SiteGEra.g_era == g_era, SiteGEra.is_physical == true())
                    .one()
                )

                vals = [
                    data_source.mprn,
                    site.code,
                    site.name,
                    data_source.account,
                    hh_format(data_source.start_date),
                    hh_format(data_source.finish_date),
                ]

                contract_func(report_context, g_contract, "virtual_bill")(data_source)
                bill = data_source.bill
                for title in bill_titles:
                    if title in bill:
                        val = make_val(bill[title])
                        del bill[title]
                    else:
                        val = ""
                    vals.append(val)

                for k in sorted(bill.keys()):
                    vals.append(k)
                    vals.append(str(bill[k]))
                writer.writerow(vals)

            month_start += relativedelta(months=1)
            month_finish = month_start + relativedelta(months=1) - HH
    except BadRequest as e:
        writer.writerow(["Problem: " + e.description])
    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)
Exemple #3
0
def _process_site(
    sess,
    report_context,
    forecast_from,
    start_date,
    finish_date,
    site,
    site_deltas,
    supply_id,
    era_maps,
    now,
    summary_titles,
    title_dict,
    era_rows,
    site_rows,
):

    calcs, displaced_era, site_gen_types = _make_calcs(
        sess,
        site,
        start_date,
        finish_date,
        supply_id,
        site_deltas,
        forecast_from,
        report_context,
        era_maps,
    )

    site_month_data = defaultdict(int)
    site_ds = chellow.computer.SiteSource(
        sess,
        site,
        start_date,
        finish_date,
        forecast_from,
        report_context,
        displaced_era,
        deltas=site_deltas,
    )

    bill_ids = set()

    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["billed-supplier-import-net-gbp"] = None
        month_data["billed-dc-import-net-gbp"] = None
        month_data["billed-mop-import-net-gbp"] = None

        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(
                f"The supplier contract {disp_supplier_contract.name} "
                f" 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"] += (
                f"For the supply {site_ds.mpan_core} the virtual bill "
                f"{disp_supplier_bill} from the contract {disp_supplier_contract.name} "
                f" does not contain the net-gbp key.")

        month_data["used-gbp"] = month_data["displaced-gbp"] = gbp

        out = ([
            now,
            None,
            disp_supplier_contract.name,
            None,
            None,
            displaced_era.meter_category,
            "displaced",
            None,
            None,
            None,
            None,
            site.code,
            site.name,
            "",
            finish_date,
        ] + [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([make_val(v) for v in out])
        for k, v in month_data.items():
            if v is not None:
                site_month_data[k] += v

    site_category = None
    site_sources = set()
    normal_reads = set()
    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
        month_data["billed-supplier-import-net-gbp"] = 0
        month_data["billed-dc-import-net-gbp"] = 0
        month_data["billed-mop-import-net-gbp"] = 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(
                        f"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"] += (
                    f"For the supply {imp_ss.mpan_core} the virtual bill " +
                    f"{imp_supplier_bill} from the contract " +
                    f"{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 sss.era.site_eras if not s.is_physical})

            for bill in sess.query(Bill).filter(
                    Bill.supply == supply,
                    Bill.start_date <= finish_date,
                    Bill.finish_date >= start_date,
            ):
                bill_ids.add(bill.id)
                bill_role_code = bill.batch.contract.market_role.code
                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, finish_date) - max(
                    bill_start, start_date)).total_seconds() + (30 * 60)
                proportion = overlap_duration / bill_duration
                month_data["billed-import-net-kwh"] += proportion * float(
                    bill.kwh)
                bill_prop_gbp = proportion * float(bill.net)
                month_data["billed-import-net-gbp"] += bill_prop_gbp
                if bill_role_code == "X":
                    month_data[
                        "billed-supplier-import-net-gbp"] += bill_prop_gbp
                elif bill_role_code == "C":
                    month_data["billed-dc-import-net-gbp"] += bill_prop_gbp
                elif bill_role_code == "M":
                    month_data["billed-mop-import-net-gbp"] += bill_prop_gbp
                else:
                    raise BadRequest("Role code not recognized.")

        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))),
            finish_date,
        ] + [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)
            for n in imp_ss.normal_reads:
                normal_reads.add((imp_mpan_core, n))
        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([make_val(v) for v in out])

    for bill in (sess.query(Bill).join(Supply).join(
            Supply.eras).join(SiteEra).filter(
                SiteEra.site == site,
                SiteEra.is_physical == true(),
                Bill.start_date <= finish_date,
                Bill.finish_date >= start_date,
            )):
        if bill.id in bill_ids:
            continue

        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
        month_data["billed-supplier-import-net-gbp"] = 0
        month_data["billed-dc-import-net-gbp"] = 0
        month_data["billed-mop-import-net-gbp"] = 0

        for bill in sess.query(Bill).filter(
                Bill.supply == bill.supply,
                Bill.start_date <= finish_date,
                Bill.finish_date >= start_date,
        ):
            bill_ids.add(bill.id)
            bill_role_code = bill.batch.contract.market_role.code
            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, finish_date) - max(
                bill_start, start_date)).total_seconds() + (30 * 60)
            proportion = overlap_duration / bill_duration
            month_data["billed-import-net-kwh"] += proportion * float(bill.kwh)
            bill_prop_gbp = proportion * float(bill.net)
            month_data["billed-import-net-gbp"] += bill_prop_gbp
            if bill_role_code == "X":
                month_data["billed-supplier-import-net-gbp"] += bill_prop_gbp
                site_month_data[
                    "billed-supplier-import-net-gbp"] += bill_prop_gbp
            elif bill_role_code == "C":
                month_data["billed-dc-import-net-gbp"] += bill_prop_gbp
                site_month_data["billed-dc-import-net-gbp"] += bill_prop_gbp
            elif bill_role_code == "M":
                month_data["billed-mop-import-net-gbp"] += bill_prop_gbp
                site_month_data["billed-mop-import-net-gbp"] += bill_prop_gbp
            else:
                raise BadRequest("Role code not recognized.")

        era = sess.execute(
            select(Era).filter(Era.supply == bill.supply).order_by(
                Era.start_date.desc())).first()[0]
        imp_supplier_contract = era.imp_supplier_contract
        exp_supplier_contract = era.exp_supplier_contract
        out = [
            now,
            era.imp_mpan_core,
            None
            if imp_supplier_contract is None else imp_supplier_contract.name,
            era.exp_mpan_core,
            None
            if exp_supplier_contract is None else exp_supplier_contract.name,
            era.meter_category,
            era.supply.source.code,
            None,
            era.supply.name,
            era.msn,
            era.pc.code,
            site.code,
            site.name,
            None,
            finish_date,
        ] + [month_data[t] for t in summary_titles]

        era_rows.append([make_val(v) for v in out])

    site_row = [
        now,
        site.code,
        site.name,
        ", ".join(
            s.code
            for s in site.find_linked_sites(sess, start_date, finish_date)),
        finish_date,
        site_category,
        ", ".join(sorted(list(site_sources))),
        ", ".join(sorted(list(site_gen_types))),
    ] + [site_month_data[k] for k in summary_titles]

    site_rows.append([make_val(v) for v in site_row])
    sess.rollback()
    return normal_reads
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()
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()
Exemple #6
0
def make_bill_row(titles, bill):
    return [make_val(bill.get(t)) for t in titles]
Exemple #7
0
def make_bill_row(titles, bill):
    return [make_val(bill.get(t)) for t in titles]