chellow 1744720514.0.0__py3-none-any.whl → 1745313690.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of chellow might be problematic. Click here for more details.

@@ -59,7 +59,7 @@ def _handle_0100(headers, pre_record, record):
59
59
  headers["issue_date"] = issue_date
60
60
  if late_payment is not None:
61
61
  headers["late_payment"] = late_payment
62
- headers["account"] = pre_record[33:41]
62
+ headers["account"] = pre_record[43:52]
63
63
  headers["reference"] = pre_record[41:46]
64
64
  headers["kwh"] = Decimal("0")
65
65
  headers["breakdown"] = defaultdict(int, {"vat": {}})
@@ -4,6 +4,7 @@ from openpyxl import load_workbook
4
4
 
5
5
  from werkzeug.exceptions import BadRequest
6
6
 
7
+ from chellow.e.computer import hh_rate
7
8
  from chellow.models import Session
8
9
  from chellow.utils import ct_datetime, parse_mpan_core, to_utc
9
10
 
@@ -16,12 +17,6 @@ def get_start_date(title_row, row, name):
16
17
  return to_utc(get_ct_date(title_row, row, name))
17
18
 
18
19
 
19
- def get_finish_date(title_row, row, name):
20
- d = get_ct_date(title_row, row, name)
21
-
22
- return to_utc(ct_datetime(d.year, d.month, d.day, 23, 30))
23
-
24
-
25
20
  def get_value(title_row, row, name):
26
21
  idx = None
27
22
  name = name.strip().lower()
@@ -61,9 +56,6 @@ def get_int(title_row, row, name):
61
56
  return int(get_value(title_row, row, name))
62
57
 
63
58
 
64
- METER_RATE = Decimal("60.00")
65
-
66
-
67
59
  class Parser:
68
60
  def __init__(self, f):
69
61
  self.book = load_workbook(f)
@@ -86,6 +78,7 @@ class Parser:
86
78
 
87
79
  def make_raw_bills(self):
88
80
  row_index = None
81
+ caches = {}
89
82
  try:
90
83
  with Session() as sess:
91
84
  bills = []
@@ -101,14 +94,30 @@ class Parser:
101
94
  mpan_core = parse_mpan_core(
102
95
  str(get_int(title_row, row, "mpan ref"))
103
96
  )
104
- start_date = get_start_date(title_row, row, "start")
97
+ start_date_ct = get_ct_date(title_row, row, "start")
98
+ start_date = to_utc(start_date_ct)
105
99
  issue_date = start_date
106
- finish_date = get_finish_date(title_row, row, "end")
100
+ finish_date_ct = get_ct_date(title_row, row, "end")
101
+ finish_date = to_utc(
102
+ ct_datetime(
103
+ finish_date_ct.year,
104
+ finish_date_ct.month,
105
+ finish_date_ct.day,
106
+ 23,
107
+ 30,
108
+ )
109
+ )
107
110
  check = get_str(title_row, row, "check")
108
111
  if check != "Billed":
109
112
  continue
110
-
111
- net = METER_RATE / 12
113
+ rates = hh_rate(sess, caches, 0, start_date)
114
+ meter_rate = rates["annual_rates"]["non_settlement"]["*"]["IP"][
115
+ "*"
116
+ ]["gbp_per_meter"]
117
+ months = (finish_date_ct.year - start_date_ct.year) * 12 + (
118
+ finish_date_ct.month - start_date_ct.month + 1
119
+ )
120
+ net = round(Decimal(float(meter_rate) / 12 * months), 2)
112
121
  vat = round(net * Decimal("0.2"), 2)
113
122
 
114
123
  breakdown = {
@@ -116,7 +125,8 @@ class Parser:
116
125
  "cop": ["5"],
117
126
  "settlement-status": ["non_settlement"],
118
127
  "msn": [msn],
119
- "meter-rate": [METER_RATE],
128
+ "meter-rate": [meter_rate],
129
+ "months": months,
120
130
  "meter-gbp": net,
121
131
  }
122
132
 
@@ -650,15 +650,15 @@ def update_vls(sess, logger, vls, dno_code, fy_start, rs_finish):
650
650
  llfc = sess.execute(q).scalar_one_or_none()
651
651
 
652
652
  if llfc is None:
653
- raise BadRequest(
653
+ logger(
654
654
  f"There is no LLFC with the code '{vl_code}' associated with the DNO "
655
- f"{dno.code} from {hh_format(fy_start)} to {hh_format(rs_finish)}."
655
+ f"{dno.dno_code} from {hh_format(fy_start)} to {hh_format(rs_finish)}."
656
656
  )
657
-
658
- vl_voltage_level = VoltageLevel.get_by_code(sess, vl["voltage_level"])
659
- llfc.voltage_level = vl_voltage_level
660
-
661
- llfc.is_substation = vl["is_substation"]
662
- if sess.is_modified(llfc):
663
- logger(f"Updated LLFC {llfc.code} of DNO {dno_code}")
664
- sess.flush()
657
+ else:
658
+ vl_voltage_level = VoltageLevel.get_by_code(sess, vl["voltage_level"])
659
+ llfc.voltage_level = vl_voltage_level
660
+
661
+ llfc.is_substation = vl["is_substation"]
662
+ if sess.is_modified(llfc):
663
+ logger(f"Updated LLFC {llfc.code} of DNO {dno_code}")
664
+ sess.flush()
@@ -0,0 +1,158 @@
1
+ import csv
2
+ import threading
3
+ import traceback
4
+
5
+ from flask import g, redirect
6
+
7
+
8
+ from sqlalchemy import null, or_, select
9
+ from sqlalchemy.orm import joinedload
10
+
11
+ from chellow.dloads import open_file
12
+ from chellow.models import Batch, Bill, Contract, Era, RSession, ReportRun, User
13
+ from chellow.utils import (
14
+ c_months_u,
15
+ csv_make_val,
16
+ hh_max,
17
+ hh_min,
18
+ hh_range,
19
+ req_date,
20
+ req_int,
21
+ )
22
+
23
+
24
+ def content(user_id, report_run_id, contract_id, months_length, finish_date):
25
+ f = writer = None
26
+ try:
27
+ with RSession() as sess:
28
+ caches = {}
29
+ contract = Contract.get_by_id(sess, contract_id)
30
+ user = User.get_by_id(sess, user_id)
31
+ f = open_file(
32
+ f"missing_bills_{contract.id}.csv", user, mode="w", newline=""
33
+ )
34
+ writer = csv.writer(f, lineterminator="\n")
35
+ titles = (
36
+ "contract_name",
37
+ "month_start",
38
+ "month_finish",
39
+ "site_code",
40
+ "site_name",
41
+ "imp_mpan_core",
42
+ "exp_mpan_core",
43
+ "account",
44
+ )
45
+ writer.writerow(titles)
46
+
47
+ months = list(
48
+ c_months_u(
49
+ finish_year=finish_date.year,
50
+ finish_month=finish_date.month,
51
+ months=months_length,
52
+ )
53
+ )
54
+
55
+ for month_start, month_finish in months:
56
+ missing_bills = {}
57
+ missing_account = {}
58
+ account_missing_tuple = hh_range(caches, month_start, month_finish)
59
+ for era in sess.scalars(
60
+ select(Era)
61
+ .where(
62
+ Era.start_date <= month_finish,
63
+ or_(Era.finish_date == null(), Era.finish_date >= month_start),
64
+ or_(
65
+ Era.mop_contract == contract,
66
+ Era.dc_contract == contract,
67
+ Era.imp_supplier_contract == contract,
68
+ Era.exp_supplier_contract == contract,
69
+ ),
70
+ )
71
+ .options(joinedload(Era.supply))
72
+ ):
73
+ chunk_start = hh_max(era.start_date, month_start)
74
+ chunk_finish = hh_min(era.finish_date, month_finish)
75
+ missing_set = set(hh_range(caches, chunk_start, chunk_finish))
76
+ if era.mop_contract == contract:
77
+ account = era.mop_account
78
+ elif era.dc_contract == contract:
79
+ account = era.dc_account
80
+ elif era.imp_supplier_contract == contract:
81
+ account = era.imp_supplier_account
82
+ elif era.imp_supplier_contract == contract:
83
+ account = era.exp_supplier_account
84
+
85
+ try:
86
+ account_missing_set = missing_account[account]
87
+ except KeyError:
88
+ account_missing_set = missing_account[account] = set(
89
+ account_missing_tuple
90
+ )
91
+ supply = era.supply
92
+
93
+ for bill in sess.scalars(
94
+ select(Bill)
95
+ .join(Batch)
96
+ .where(
97
+ Batch.contract == contract,
98
+ Bill.supply == supply,
99
+ Bill.start_date <= chunk_finish,
100
+ Bill.finish_date >= chunk_start,
101
+ )
102
+ ):
103
+ found_set = set(
104
+ hh_range(caches, bill.start_date, bill.finish_date)
105
+ )
106
+ missing_set.difference_update(found_set)
107
+ account_missing_set.difference_update(found_set)
108
+
109
+ if len(missing_set) > 0:
110
+ site = era.get_physical_site(sess)
111
+
112
+ values = {
113
+ "contract_id": contract.id,
114
+ "contract_name": contract.name,
115
+ "month_start": month_start,
116
+ "month_finish": month_finish,
117
+ "era_id": era.id,
118
+ "supply_id": supply.id,
119
+ "imp_mpan_core": era.imp_mpan_core,
120
+ "exp_mpan_core": era.exp_mpan_core,
121
+ "site_id": site.id,
122
+ "site_code": site.code,
123
+ "site_name": site.name,
124
+ "account": account,
125
+ "market_role_code": contract.market_role.code,
126
+ }
127
+ missing_bills[era.id] = values
128
+ for era_id, values in missing_bills.items():
129
+ if len(missing_account[values["account"]]) > 0:
130
+ writer.writerow(csv_make_val(values[t]) for t in titles)
131
+ ReportRun.w_insert_row(report_run_id, "", titles, values, {})
132
+
133
+ except BaseException:
134
+ msg = traceback.format_exc()
135
+ print(msg)
136
+ if writer is not None:
137
+ writer.writerow([msg])
138
+ finally:
139
+ ReportRun.w_update(report_run_id, "finished")
140
+ if f is not None:
141
+ f.close()
142
+
143
+
144
+ def do_get(sess):
145
+ contract_id = req_int("contract_id")
146
+ months = req_int("months")
147
+ finish_date = req_date("finish", resolution="month")
148
+ report_run = ReportRun.insert(
149
+ sess,
150
+ "missing_e_bills",
151
+ g.user,
152
+ "missing_e_bills",
153
+ {},
154
+ )
155
+ sess.commit()
156
+ args = g.user.id, report_run.id, contract_id, months, finish_date
157
+ threading.Thread(target=content, args=args).start()
158
+ return redirect(f"/report_runs/{report_run.id}", 303)
@@ -97,7 +97,18 @@
97
97
  <input type="submit" value="Download">
98
98
  </fieldset>
99
99
  </form>
100
- <br>
100
+
101
+ <form action="/reports/missing_bills">
102
+ <fieldset>
103
+ <legend>Download Missing Bills</legend>
104
+ <input type="hidden" name="contract_id" value="{{dc_contract.id}}">
105
+
106
+ <label>Months</label> <input name="months" value="1" maxlength="2" size="2">
107
+ <label>Last Month</label> {{input_date('finish', last_month_finish, 'month')}}
108
+ <input type="submit" value="Download">
109
+ </fieldset>
110
+ </form>
111
+
101
112
  <h3>Script</h3>
102
113
 
103
114
  <pre>{{dc_contract.charge_script}}</pre>
@@ -76,6 +76,17 @@
76
76
  <input type="submit" value="Download"/>
77
77
  </fieldset>
78
78
  </form>
79
+
80
+ <form action="/reports/missing_bills">
81
+ <fieldset>
82
+ <legend>Download Missing Bills</legend>
83
+ <input type="hidden" name="contract_id" value="{{contract.id}}">
84
+
85
+ <label>Months</label> <input name="months" value="1" maxlength="2" size="2">
86
+ <label>Last Month</label> {{input_date('finish', last_month_finish, 'month')}}
87
+ <input type="submit" value="Download">
88
+ </fieldset>
89
+ </form>
79
90
  <br>
80
91
  <h2>Script</h2>
81
92
  <pre>{{contract.charge_script}}</pre>
@@ -97,6 +97,17 @@
97
97
  </fieldset>
98
98
  </form>
99
99
 
100
+ <form action="/reports/missing_bills">
101
+ <fieldset>
102
+ <legend>Download Missing Bills</legend>
103
+ <input type="hidden" name="contract_id" value="{{contract.id}}">
104
+
105
+ <label>Months</label> <input name="months" value="1" maxlength="2" size="2">
106
+ <label>Last Month</label> {{input_date('finish', month_finish, 'month')}}
107
+ <input type="submit" value="Download">
108
+ </fieldset>
109
+ </form>
110
+
100
111
  <h2>Script</h2>
101
112
 
102
113
  <pre>{{contract.charge_script}}</pre>
@@ -0,0 +1,97 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}
4
+ &raquo; Report Runs &raquo; {{run.id}}
5
+ {% endblock %}
6
+
7
+ {% block nav %}
8
+ <a href="/report_runs">Report Runs</a> &raquo; {{run.id}}
9
+ {% endblock %}
10
+
11
+ {% block content %}
12
+ <table class="sticky">
13
+ <caption>Missing Electricity Bills Summary</caption>
14
+ <thead>
15
+ <tr>
16
+ <th>Date Created</th>
17
+ <th>Created By</th>
18
+ <th>State</th>
19
+ <th>Number Of Rows</th>
20
+ <th>Delete</th>
21
+ <th>Download Spreadsheet</th>
22
+ </tr>
23
+ </thead>
24
+ <tbody>
25
+ <tr>
26
+ <td>{{run.date_created|hh_format}}</td>
27
+ <td>{{run.creator}}</td>
28
+ <td>{{run.state}}</td>
29
+ <td>{{rows|length}}</td>
30
+ <td>
31
+ <form hx-delete="/report_runs/{{run.id}}/edit"
32
+ hx-confirm="Are you sure you want to delete this report run?">
33
+ <fieldset style="border: none;">
34
+ <input type="submit" name="delete" value="Delete">
35
+ </fieldset>
36
+ </form>
37
+ </td>
38
+ <td>
39
+ <a href="/report_runs/{{run.id}}/spreadsheet">Download</a>
40
+ </td>
41
+ </tr>
42
+ </tbody>
43
+ </table>
44
+
45
+ <table class="sticky">
46
+ <caption>
47
+ Missing Electricity Bills
48
+ </caption>
49
+ <thead>
50
+ <tr>
51
+ <th>Contract</th>
52
+ <th>Month</th>
53
+ <th>Supply</th>
54
+ <th>Import MPAN</th>
55
+ <th>Export MPAN</th>
56
+ <th>Account</th>
57
+ <th>Site</th>
58
+ </tr>
59
+ </thead>
60
+ <tbody>
61
+ {% for row in rows %}
62
+ {% set values = row.data['values'] %}
63
+ <tr>
64
+ <td>
65
+ {% if values['market_role_code'] == 'M' %}
66
+ <a href="/e/mop_contracts/{{values['contract_id']}}">{{values['contract_name']}}</a>
67
+ {% elif values['market_role_code'] == 'C' %}
68
+ <a href="/e/dc_contracts/{{values['contract_id']}}">{{values['contract_name']}}</a>
69
+ {% elif values['market_role_code'] == 'X' %}
70
+ <a href="/e/supplier_contracts/{{values['contract_id']}}">{{values['contract_name']}}</a>
71
+ {% endif %}
72
+ </td>
73
+ <td>{{values['month_start'][:7]}}</td>
74
+ <td>
75
+ <a href="/e/supplies/{{values['supply_id']}}">View</a>
76
+ </td>
77
+ <td>
78
+ {% if values['imp_mpan_core'] is not none %}
79
+ {{values['imp_mpan_core']}}
80
+ {% endif %}
81
+ </td>
82
+ <td>
83
+ {% if values['exp_mpan_core'] is not none %}
84
+ {{values['exp_mpan_core']}}
85
+ {% endif %}
86
+ </td>
87
+ <td>{{values['account']}}</td>
88
+ <td>
89
+ <a href="/sites/{{values['site_id']}}" title="{{values['site_name']}}">
90
+ {{values['site_code']}}
91
+ </a>
92
+ </td>
93
+ </tr>
94
+ {% endfor %}
95
+ </tbody>
96
+ </table>
97
+ {% endblock %}
chellow/utils.py CHANGED
@@ -67,12 +67,15 @@ def req_zish(name):
67
67
  def req_date(prefix, resolution="minute"):
68
68
  year = req_int(f"{prefix}_year")
69
69
  month = req_int(f"{prefix}_month")
70
- day = req_int(f"{prefix}_day")
71
70
 
72
71
  try:
73
- if resolution == "day":
72
+ if resolution == "month":
73
+ d = ct_datetime(year, month)
74
+ elif resolution == "day":
75
+ day = req_int(f"{prefix}_day")
74
76
  d = ct_datetime(year, month, day)
75
77
  elif resolution == "minute":
78
+ day = req_int(f"{prefix}_day")
76
79
  hour = req_int(f"{prefix}_hour")
77
80
  minute = req_int(f"{prefix}_minute")
78
81
  d = ct_datetime(year, month, day, hour, minute)
chellow/views.py CHANGED
@@ -1538,6 +1538,19 @@ def report_run_get(run_id):
1538
1538
  run=run,
1539
1539
  rows=rows,
1540
1540
  )
1541
+ elif run.name == "missing_e_bills":
1542
+ rows = g.sess.scalars(
1543
+ select(ReportRunRow)
1544
+ .filter(ReportRunRow.report_run == run)
1545
+ .order_by(
1546
+ ReportRunRow.data["values"]["month_start"],
1547
+ )
1548
+ ).all()
1549
+ return render_template(
1550
+ "report_run_missing_e_bills.html",
1551
+ run=run,
1552
+ rows=rows,
1553
+ )
1541
1554
 
1542
1555
  else:
1543
1556
  order_by = "row.id"
@@ -1561,12 +1574,12 @@ def report_run_get(run_id):
1561
1574
  )
1562
1575
 
1563
1576
 
1564
- @home.route("/report_runs/<int:run_id>", methods=["POST"])
1565
- def report_run_post(run_id):
1577
+ @home.route("/report_runs/<int:run_id>", methods=["DELETE"])
1578
+ def report_run_delete(run_id):
1566
1579
  run = g.sess.query(ReportRun).filter(ReportRun.id == run_id).one()
1567
1580
  run.delete(g.sess)
1568
1581
  g.sess.commit()
1569
- return redirect("/report_runs", 303)
1582
+ return hx_redirect("/report_runs", 303)
1570
1583
 
1571
1584
 
1572
1585
  @home.route("/report_runs/<int:run_id>/spreadsheet")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chellow
3
- Version: 1744720514.0.0
3
+ Version: 1745313690.0.0
4
4
  Summary: Web Application for checking UK energy bills.
5
5
  Project-URL: Homepage, https://github.com/WessexWater/chellow
6
6
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
@@ -12,8 +12,8 @@ chellow/proxy.py,sha256=cVXIktPlX3tQ1BYcwxq0nJXKE6r3DtFTtfFHPq55HaM,1351
12
12
  chellow/rate_server.py,sha256=fg-Pf_9Hk3bXmC9riPQNGQxBvLvBa_WtNYdwDCjnCSg,5678
13
13
  chellow/rrun.py,sha256=1Kt2q_K9UoDG_nsZz-Q6XJiMNKroWqlqFdxn2M6Q8CA,2088
14
14
  chellow/testing.py,sha256=Dj2c1NX8lVlygueOrh2eyYawLW6qKEHxNhXVVUaNRO0,3637
15
- chellow/utils.py,sha256=Ej7dsbQ6Ee8X2aZ7B2Vs-hUFCsMABioAdOV1DJjwY-0,19293
16
- chellow/views.py,sha256=Ax8TW5dOoWN1G7zmmO4_X0af_9gftKU0HAHoPpkYNIc,84883
15
+ chellow/utils.py,sha256=i3GQK9MIcweosZk2gi-nX_IFq2DxURAJDyNoLBg6YwM,19421
16
+ chellow/views.py,sha256=GVmmChaMaFmZmcsgvR9Z5xfSh4Y1mPEBDR90kiZH5Xk,85292
17
17
  chellow/e/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
18
  chellow/e/aahedc.py,sha256=d2usudp7KYWpU6Pk3fal5EQ47EbvkvKeaFGylnb3NWw,606
19
19
  chellow/e/bill_importer.py,sha256=7UcnqNlKbJc2GhW9gy8sDp9GuqambJVpZLvbafOZztA,7411
@@ -22,7 +22,7 @@ chellow/e/bsuos.py,sha256=hdP9vnOJSuZl46OAkJeUg1XJYvYIBj4J6Sqce1Hy9Vs,15542
22
22
  chellow/e/ccl.py,sha256=30dh_SvlgzsTQPPAJNZWILaMvbeDsv9-P-S1JxS5_SQ,3184
23
23
  chellow/e/cfd.py,sha256=CWLdYeNjgqT6Ro8YRf4vhwXIAJ2aV4Wi6HLNClVSeaQ,14260
24
24
  chellow/e/computer.py,sha256=aGti5aXRTdC85M-WRiAoZkC_76sqfAiP-79ggWZF09Q,68020
25
- chellow/e/dno_rate_parser.py,sha256=A5TP6KjyfT5lVWh7dX4SiXRi6wnf2lGv-H_T4Sod8CI,21731
25
+ chellow/e/dno_rate_parser.py,sha256=NOVfS9HRDsc0rO282hU-IdrcuvMlC7VE8RySqd_5eT0,21762
26
26
  chellow/e/duos.py,sha256=RHrn93I1ASO2uYkuF18qlhG4p-jpuJhd_g3o69wtP4U,31004
27
27
  chellow/e/elexon.py,sha256=ALhXS9Es7PV0z9ukPbIramn3cf3iLyFi-PMWPSm5iOs,5487
28
28
  chellow/e/energy_management.py,sha256=aXC2qlGt3FAODlNl_frWzVYAQrJLP8FFOiNX3m-QE_Y,12388
@@ -59,8 +59,8 @@ chellow/e/bill_parsers/gdf_csv.py,sha256=ZfK3Oc6oP28p_P9DIevLNB_zW2WLcEJ3Lvb1gL3
59
59
  chellow/e/bill_parsers/haven_csv.py,sha256=0uENq8IgVNqdxfBQMBxLTSZWCOuDHXZC0xzk52SbfyE,13652
60
60
  chellow/e/bill_parsers/haven_edi.py,sha256=YGPHRxPOhje9s32jqPHHELni2tooOYj3cMC_qaZVPq4,16107
61
61
  chellow/e/bill_parsers/haven_edi_tprs.py,sha256=ZVX9CCqUybsot_Z0BEOJPvl9x5kSr7fEWyuJXvZDcz4,11841
62
- chellow/e/bill_parsers/mm.py,sha256=MmGPNWYPY9UURvKwAHYpWQF2C8YuF8D1IVH9xptemDs,11227
63
- chellow/e/bill_parsers/nonsettlement_dc_stark_xlsx.py,sha256=yogXTuQHGRL7IiqvRWr2C9V24ez1j9Yx0128UygPE_k,4723
62
+ chellow/e/bill_parsers/mm.py,sha256=tv7SAIbwFJYCiHz1ZwTV9QJeGkSo3-KuOp--DUimzLI,11227
63
+ chellow/e/bill_parsers/nonsettlement_dc_stark_xlsx.py,sha256=YvQ0Q6HlZ4XSk6Phx1UWaTSj8FREVjwQe8nrpiLVzbU,5458
64
64
  chellow/e/bill_parsers/settlement_dc_stark_xlsx.py,sha256=osCpUYUdLcPtlo7ngXWGw0ImnxssLa1fOSejMwe51-k,6381
65
65
  chellow/e/bill_parsers/sse_edi.py,sha256=L85DOfNkqexeEIEr8pCBn_2sHJI-zEaw6cogpE3YyYM,15204
66
66
  chellow/e/bill_parsers/sww_xls.py,sha256=QEjiuvwvr5FuWCfqqVw8LaA_vZyAKsvRAS5fw3xtFhM,7533
@@ -107,6 +107,7 @@ chellow/reports/report_g_supplies_snapshot.py,sha256=9xB6RDrnbgxuomMcP1b1yEP4kOn
107
107
  chellow/reports/report_g_supply_virtual_bill.py,sha256=EaYrB8PHJIXrUuhiZ7dwUlbNBkuyJebQHrdc308_z1o,3653
108
108
  chellow/reports/report_g_virtual_bills.py,sha256=20vHa5LGQwOAlJlaGJaGszZrrbT0PMOZJf6hSxU2hIQ,4528
109
109
  chellow/reports/report_g_virtual_bills_hh.py,sha256=gaiLEmKTpq6JsfZ1p0SdCDuPvzvigXp6z88gHRCA63w,3416
110
+ chellow/reports/report_missing_bills.py,sha256=3uWA6Wyskn30tUDOV_W6u_009flfKzua7vDh_jsBDaM,5956
110
111
  chellow/reports/report_sscs.py,sha256=fQWyVG-gdg37DyNHgpNARpSxIwTl7mCn20fDLwx9oHg,3214
111
112
  chellow/reports/report_supply_contacts.py,sha256=pvwlInaPYV_pa9MMK6vh854plHFwv3m5zo5xulR1g5I,3599
112
113
  chellow/static/css/chellow.css,sha256=dnkuj9Z1BCOV_L2Y26lDd2QlTmFFhATa1YvwPVch1Oc,5375
@@ -145,6 +146,7 @@ chellow/templates/report_run_asset_comparison.html,sha256=VYCCUmIC7Mfe7uuaAHb6ih
145
146
  chellow/templates/report_run_bill_check.html,sha256=H2ayoBL7EgKMq2Nwq5VjE_TNvcIKcqeCm0alQWLIw78,5084
146
147
  chellow/templates/report_run_ecoes_comparison.html,sha256=VmkT5ypWLP8qZS6NbDTC4yDaG7mnUlxZz7EV8xkHGZw,4086
147
148
  chellow/templates/report_run_g_bill_check.html,sha256=tOXl_mjR__foYKiOYflJbK-459actAtjzv8rfuL3TwM,4851
149
+ chellow/templates/report_run_missing_e_bills.html,sha256=l5idQhfaNhMvvzIRv-iqCpeDnYl_wgs6-mZMBOmuyR8,2447
148
150
  chellow/templates/report_run_monthly_duration_org.html,sha256=gGNGJ4Q50q4BtIMi98rhO-7NqRHcsFUmbj2qzeOLejw,1713
149
151
  chellow/templates/report_run_row.html,sha256=bmtcdqJaS1CXpL0i8PuqvmeF98jKNYX5-mnQu-OuDKQ,3791
150
152
  chellow/templates/report_run_row_bill_check.html,sha256=aC2LMu_6NvmTN3ZdxHJPPPczyxPN6hg0F-PPcqIWUws,4683
@@ -200,7 +202,7 @@ chellow/templates/e/dc_bill_add.html,sha256=73Sn_MKBsUuYYnDfUMCdX1Dul6GimMC9YXk6
200
202
  chellow/templates/e/dc_bill_edit.html,sha256=0GsN-ZIc4q-z_xs8igC2ZS6t4soo2SvB3qRA6iC-AuM,2707
201
203
  chellow/templates/e/dc_bill_import.html,sha256=NHjMSoFizvFQIaPWuVE3nTCtMDTzJB0XmH8jXfV1tiA,2188
202
204
  chellow/templates/e/dc_bill_imports.html,sha256=lCaUR47r9KPr0VrQhEvVEaKexM5R_nmkxtzgpWZ0e9s,2135
203
- chellow/templates/e/dc_contract.html,sha256=b6DLDrGdzN9Rri56pFvfpE7QZKYXGHib2veYAztuHlg,2352
205
+ chellow/templates/e/dc_contract.html,sha256=MqkRck0qCgxXrHSbYTfyqjf_bAbIfMy93b9kdqH0pCQ,2746
204
206
  chellow/templates/e/dc_contract_edit.html,sha256=IObmbHQmeZ_LSpnYgabmhoSNUR3aPmm-Jk5nJLM_u74,1706
205
207
  chellow/templates/e/dc_contract_hh_import.html,sha256=JncR3L6cOK4jghsGyr-itEqlIemXBXt3kL09wpqnQSE,856
206
208
  chellow/templates/e/dc_contract_hh_imports.html,sha256=eXFDGyzSgag4JRism81_p5yTzQOjCIXaVkQ8tl3dDcM,8172
@@ -257,7 +259,7 @@ chellow/templates/e/mop_bill_add.html,sha256=fjoJj6QvcCk28rPD0Z6tIXrFYZ7ygN6lIXu
257
259
  chellow/templates/e/mop_bill_edit.html,sha256=Hld9b-ckLCd9N7hleugg0BuwsZrmkvDeiJ5yLW8z-Js,2748
258
260
  chellow/templates/e/mop_bill_import.html,sha256=sSVCZnarru0GKYFW1uuP0f1Ix9iNFDtEypQ93hqeUsk,3201
259
261
  chellow/templates/e/mop_bill_imports.html,sha256=jIhWaOuk4hYj9jhXBUxQ7C8v9HJljWfOGGeu1rZa1PI,1610
260
- chellow/templates/e/mop_contract.html,sha256=CyuBhj6da1-TiaomXSDD8JD449Ksu8QvIZODHmsE804,1748
262
+ chellow/templates/e/mop_contract.html,sha256=M6_pZuNpjdh9EaSGA5UsqSFIAvB0ABOehJ7s5oQ3pvk,2144
261
263
  chellow/templates/e/mop_contract_add.html,sha256=qyjDNz_pOVgfrsKaju0KwxBKJnWF9RxUa-8gUtaOc60,738
262
264
  chellow/templates/e/mop_contract_edit.html,sha256=4DbyiKbWRdliQGPh0wlh4dEuhD-R4-3XRzXoNMLfFD4,1719
263
265
  chellow/templates/e/mop_contracts.html,sha256=2TPVkeUefsYOVZIiiLMPJgwcrxhvjk8Io4UKvgdQ2AY,768
@@ -317,7 +319,7 @@ chellow/templates/e/supplier_bill_add.html,sha256=BsD-Zh7d9auiqJ61VPHiQrP8u8rTcw
317
319
  chellow/templates/e/supplier_bill_edit.html,sha256=oxZrMcMwrvluJSPxD4yfM9mWNeugoguAwT_ai9Ynl88,2732
318
320
  chellow/templates/e/supplier_bill_import.html,sha256=2_VvBoNE838UwuN0AiMwIrzqxQmWBo5DGY0lY833Bpk,5265
319
321
  chellow/templates/e/supplier_bill_imports.html,sha256=9iTNGWKn9XjQTBP1Sepbo0QVNlgKh7EfizXapam7I6s,9356
320
- chellow/templates/e/supplier_contract.html,sha256=oVGrYGIbCb-7MmpFQaXeTNRKBKy8GoGCWICWgo5E4xI,2863
322
+ chellow/templates/e/supplier_contract.html,sha256=TOm5ey5b1tm0A-8g2EmZhY7WddbGDih1B4ieJknA8Ns,3254
321
323
  chellow/templates/e/supplier_contract_add.html,sha256=gsozEtF24lzYi_Bb4LTenvh62tCt7dQ4CwaIz7rFck4,899
322
324
  chellow/templates/e/supplier_contract_edit.html,sha256=Afwtn0l8XRbt86bMOru2AjjvctoUkieD052aY0B2mDc,1463
323
325
  chellow/templates/e/supplier_contracts.html,sha256=VwWD4q88Fynz7vioFSAsyH6RR_1SyQQl6bQwzL-W1m0,1508
@@ -380,6 +382,6 @@ chellow/templates/g/supply_note_edit.html,sha256=b8mB6_ucBwoljp03iy6AgVaZUhGw3-1
380
382
  chellow/templates/g/supply_notes.html,sha256=6epNmZ3NKdXZz27fvmRUGeffg_oc1kmwuBeyRzQe3Rg,854
381
383
  chellow/templates/g/unit.html,sha256=KouNVU0-i84afANkLQ_heJ0uDfJ9H5A05PuLqb8iCN8,438
382
384
  chellow/templates/g/units.html,sha256=p5Nd-lAIboKPEOO6N451hx1bcKxMg4BDODnZ-43MmJc,441
383
- chellow-1744720514.0.0.dist-info/METADATA,sha256=h25ZnkwR-pmuFVXtxncX-IM8v7L7Z_yXQ4DZ_H-HlYw,12238
384
- chellow-1744720514.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
385
- chellow-1744720514.0.0.dist-info/RECORD,,
385
+ chellow-1745313690.0.0.dist-info/METADATA,sha256=6L9prKczSdFxE1p_b8WJ_f16sePhQBrdB5ZLbBmbnTk,12238
386
+ chellow-1745313690.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
387
+ chellow-1745313690.0.0.dist-info/RECORD,,