chellow 1755614564.0.0__py3-none-any.whl → 1759155233.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.

Files changed (75) hide show
  1. chellow/e/bill_importer.py +136 -80
  2. chellow/e/bill_parsers/activity_mop_stark_xlsx.py +99 -86
  3. chellow/e/bill_parsers/annual_mop_stark_xlsx.py +78 -61
  4. chellow/e/bill_parsers/csv.py +139 -101
  5. chellow/e/bill_parsers/drax_edi.py +65 -88
  6. chellow/e/bill_parsers/engie_edi.py +187 -255
  7. chellow/e/bill_parsers/engie_xls.py +153 -167
  8. chellow/e/bill_parsers/haven_edi.py +189 -228
  9. chellow/e/bill_parsers/haven_edi_tprs.py +67 -67
  10. chellow/e/bill_parsers/nonsettlement_dc_stark_xlsx.py +75 -66
  11. chellow/e/bill_parsers/settlement_dc_stark_xlsx.py +229 -126
  12. chellow/e/bill_parsers/sse_edi.py +107 -75
  13. chellow/e/bill_parsers/sww_xls.py +78 -91
  14. chellow/e/computer.py +1 -1
  15. chellow/e/views.py +626 -281
  16. chellow/edi_lib.py +4 -27
  17. chellow/models.py +92 -3
  18. chellow/reports/report_111.py +478 -616
  19. chellow/reports/report_247.py +96 -137
  20. chellow/templates/e/dc_batch.html +110 -157
  21. chellow/templates/e/dc_batch_add.html +2 -3
  22. chellow/templates/e/dc_batch_edit.html +42 -46
  23. chellow/templates/e/dc_batch_file.html +2 -3
  24. chellow/templates/e/dc_batch_file_edit.html +28 -40
  25. chellow/templates/e/dc_batch_upload_file.html +68 -0
  26. chellow/templates/e/dc_batches.html +2 -1
  27. chellow/templates/e/dc_batches_edit.html +26 -0
  28. chellow/templates/e/dc_bill.html +27 -5
  29. chellow/templates/e/dc_bill_add.html +4 -4
  30. chellow/templates/e/dc_bill_edit.html +43 -63
  31. chellow/templates/e/dc_bill_import.html +1 -1
  32. chellow/templates/e/dc_bill_import_contract.html +130 -0
  33. chellow/templates/e/dc_contract.html +1 -1
  34. chellow/templates/e/dc_element.html +41 -0
  35. chellow/templates/e/dc_element_add.html +36 -0
  36. chellow/templates/e/dc_element_edit.html +49 -0
  37. chellow/templates/e/dc_rate_script_edit.html +27 -43
  38. chellow/templates/e/mop_batch.html +105 -152
  39. chellow/templates/e/mop_batch_add.html +2 -3
  40. chellow/templates/e/mop_batch_edit.html +43 -51
  41. chellow/templates/e/mop_batch_upload_file.html +71 -5
  42. chellow/templates/e/mop_batches.html +2 -1
  43. chellow/templates/e/mop_batches_edit.html +26 -0
  44. chellow/templates/e/mop_bill.html +31 -8
  45. chellow/templates/e/mop_bill_add.html +7 -27
  46. chellow/templates/e/mop_bill_import.html +1 -1
  47. chellow/templates/e/mop_bill_import_contract.html +130 -0
  48. chellow/templates/e/mop_contract.html +4 -5
  49. chellow/templates/e/mop_element.html +41 -0
  50. chellow/templates/e/mop_element_add.html +36 -0
  51. chellow/templates/e/mop_element_edit.html +49 -0
  52. chellow/templates/e/supplier_batch.html +3 -7
  53. chellow/templates/e/supplier_batch_add.html +2 -2
  54. chellow/templates/e/supplier_batch_edit.html +1 -1
  55. chellow/templates/e/supplier_batch_file.html +3 -5
  56. chellow/templates/e/supplier_batch_file_add.html +18 -11
  57. chellow/templates/e/supplier_batch_upload_file.html +83 -9
  58. chellow/templates/e/supplier_batches.html +4 -4
  59. chellow/templates/e/supplier_batches_edit.html +26 -0
  60. chellow/templates/e/supplier_bill.html +29 -6
  61. chellow/templates/e/supplier_bill_add.html +3 -3
  62. chellow/templates/e/supplier_bill_import.html +1 -1
  63. chellow/templates/e/supplier_bill_import_contract.html +118 -0
  64. chellow/templates/e/supplier_contract.html +1 -1
  65. chellow/templates/e/supplier_element.html +45 -0
  66. chellow/templates/e/supplier_element_add.html +36 -0
  67. chellow/templates/e/supplier_element_edit.html +51 -0
  68. chellow/templates/report_run_bill_check.html +137 -179
  69. chellow/templates/report_run_row_bill_check.html +182 -179
  70. chellow/views.py +55 -65
  71. {chellow-1755614564.0.0.dist-info → chellow-1759155233.0.0.dist-info}/METADATA +2 -2
  72. {chellow-1755614564.0.0.dist-info → chellow-1759155233.0.0.dist-info}/RECORD +73 -60
  73. chellow/e/bill_parsers/drax_element_edi.py +0 -459
  74. chellow/templates/e/supplier_bill_imports.html +0 -421
  75. {chellow-1755614564.0.0.dist-info → chellow-1759155233.0.0.dist-info}/WHEEL +0 -0
chellow/e/views.py CHANGED
@@ -21,7 +21,19 @@ from flask import (
21
21
  request,
22
22
  )
23
23
 
24
- from sqlalchemy import Float, case, cast, false, func, null, or_, select, text, true
24
+ from sqlalchemy import (
25
+ Float,
26
+ case,
27
+ cast,
28
+ delete,
29
+ false,
30
+ func,
31
+ null,
32
+ or_,
33
+ select,
34
+ text,
35
+ true,
36
+ )
25
37
  from sqlalchemy.orm import aliased, joinedload
26
38
 
27
39
 
@@ -45,6 +57,7 @@ from chellow.models import (
45
57
  Contract,
46
58
  Cop,
47
59
  DtcMeterType,
60
+ Element,
48
61
  EnergisationStatus,
49
62
  Era,
50
63
  GeneratorType,
@@ -478,9 +491,8 @@ def dc_auto_importer_post(contract_id):
478
491
  )
479
492
 
480
493
 
481
- @e.route("/dc_batches")
482
- def dc_batches_get():
483
- contract_id = req_int("dc_contract_id")
494
+ @e.route("/dc_contracts/<int:contract_id>/batches")
495
+ def dc_batches_get(contract_id):
484
496
  contract = Contract.get_dc_by_id(g.sess, contract_id)
485
497
  batches = g.sess.execute(
486
498
  select(
@@ -498,6 +510,30 @@ def dc_batches_get():
498
510
  return render_template("dc_batches.html", contract=contract, batches=batches)
499
511
 
500
512
 
513
+ @e.route("/dc_contracts/<int:contract_id>/batches/edit")
514
+ def dc_batches_edit_get(contract_id):
515
+ contract = Contract.get_dc_by_id(g.sess, contract_id)
516
+ return render_template("dc_batches_edit.html", contract=contract)
517
+
518
+
519
+ @e.route("/dc_contracts/<int:contract_id>/batches/edit", methods=["POST"])
520
+ def dc_batches_edit_post(contract_id):
521
+ try:
522
+ contract = Contract.get_dc_by_id(g.sess, contract_id)
523
+ for batch in g.sess.scalars(select(Batch).where(Batch.contract == contract)):
524
+ if len(batch.files) > 0:
525
+ g.sess.execute(delete(Bill).where(Bill.batch == batch))
526
+ g.sess.commit()
527
+ import_id = chellow.e.bill_importer.start_bill_import_contract(contract)
528
+ return hx_redirect(f"/dc_bill_imports/{import_id}")
529
+ except BadRequest as e:
530
+ flash(e.description)
531
+ return make_response(
532
+ render_template("dc_batches_edit.html", contract=contract),
533
+ 400,
534
+ )
535
+
536
+
501
537
  @e.route("/dc_batches/<int:batch_id>")
502
538
  def dc_batch_get(batch_id):
503
539
  batch = Batch.get_by_id(g.sess, batch_id)
@@ -602,7 +638,7 @@ def dc_batch_post(batch_id):
602
638
  )
603
639
 
604
640
 
605
- @e.route("/dc_contracts/<int:contract_id>/add_batch")
641
+ @e.route("/dc_contracts/<int:contract_id>/batches/add")
606
642
  def dc_batch_add_get(contract_id):
607
643
  contract = Contract.get_dc_by_id(g.sess, contract_id)
608
644
  batches = (
@@ -622,7 +658,7 @@ def dc_batch_add_get(contract_id):
622
658
  )
623
659
 
624
660
 
625
- @e.route("/dc_contracts/<int:contract_id>/add_batch", methods=["POST"])
661
+ @e.route("/dc_contracts/<int:contract_id>/batches/add", methods=["POST"])
626
662
  def dc_batch_add_post(contract_id):
627
663
  try:
628
664
  contract = Contract.get_dc_by_id(g.sess, contract_id)
@@ -650,19 +686,36 @@ def dc_batch_edit_get(batch_id):
650
686
  return render_template("dc_batch_edit.html", batch=batch)
651
687
 
652
688
 
689
+ @e.route("/dc_batches/<int:batch_id>/edit", methods=["DELETE"])
690
+ def dc_batch_edit_delete(batch_id):
691
+ try:
692
+ batch = Batch.get_by_id(g.sess, batch_id)
693
+ contract = batch.contract
694
+ batch.delete(g.sess)
695
+ g.sess.commit()
696
+ return hx_redirect(f"/dc_contracts/{contract.id}/batches", 303)
697
+ except BadRequest as e:
698
+ flash(e.description)
699
+ return make_response(render_template("dc_batch_edit.html", batch=batch), 400)
700
+
701
+
653
702
  @e.route("/dc_batches/<int:batch_id>/edit", methods=["POST"])
654
703
  def dc_batch_edit_post(batch_id):
655
704
  try:
656
705
  batch = Batch.get_by_id(g.sess, batch_id)
657
- if "delete" in request.values:
658
- contract = batch.contract
659
- batch.delete(g.sess)
706
+ if "delete_bills" in request.values:
707
+ g.sess.execute(delete(Bill).where(Bill.batch == batch))
660
708
  g.sess.commit()
661
- return chellow_redirect(f"/dc_batches?dc_contract_id={contract.id}", 303)
662
- elif "delete_bills" in request.values:
663
- g.sess.query(Bill).filter(Bill.batch == batch).delete(False)
709
+ flash("Bills successfully deleted.")
710
+ return hx_redirect(f"/dc_batches/{batch.id}", 303)
711
+ elif "import_bills" in request.values:
712
+ import_id = chellow.e.bill_importer.start_bill_import(batch)
713
+ return hx_redirect(f"/dc_bill_imports/{import_id}", 303)
714
+ elif "delete_import_bills" in request.values:
715
+ g.sess.execute(delete(Bill).where(Bill.batch == batch))
664
716
  g.sess.commit()
665
- return chellow_redirect(f"/dc_batches/{batch.id}", 303)
717
+ import_id = chellow.e.bill_importer.start_bill_import(batch)
718
+ return hx_redirect(f"/dc_bill_imports/{import_id}", 303)
666
719
  else:
667
720
  reference = req_str("reference")
668
721
  description = req_str("description")
@@ -742,25 +795,42 @@ def dc_batch_file_edit_get(file_id):
742
795
  )
743
796
 
744
797
 
798
+ @e.route("/dc_batch_files/<int:file_id>/edit", methods=["DELETE"])
799
+ def dc_batch_file_edit_delete(file_id):
800
+ batch_file = None
801
+ try:
802
+ batch_file = BatchFile.get_by_id(g.sess, file_id)
803
+
804
+ batch_id = batch_file.batch.id
805
+ batch_file.delete(g.sess)
806
+ g.sess.commit()
807
+ flash("Deletion successful")
808
+ return chellow_redirect(f"/dc_batches/{batch_id}", 303)
809
+
810
+ except BadRequest as e:
811
+ flash(e.description)
812
+ parser_names = chellow.bill_importer.find_parser_names()
813
+ return make_response(
814
+ render_template(
815
+ "dc_batch_file_edit.html",
816
+ batch_file=batch_file,
817
+ parser_names=parser_names,
818
+ ),
819
+ 400,
820
+ )
821
+
822
+
745
823
  @e.route("/dc_batch_files/<int:file_id>/edit", methods=["POST"])
746
824
  def dc_batch_file_edit_post(file_id):
747
825
  batch_file = None
748
826
  try:
749
827
  batch_file = BatchFile.get_by_id(g.sess, file_id)
750
828
 
751
- if "delete" in request.values:
752
- batch_id = batch_file.batch.id
753
- batch_file.delete(g.sess)
754
- g.sess.commit()
755
- flash("Deletion successful")
756
- return chellow_redirect(f"/dc_batches/{batch_id}", 303)
757
-
758
- else:
759
- parser_name = req_str("parser_name")
760
- batch_file.update(parser_name)
761
- g.sess.commit()
762
- flash("Update successful")
763
- return chellow_redirect(f"/dc_batch_files/{batch_file.id}", 303)
829
+ parser_name = req_str("parser_name")
830
+ batch_file.update(parser_name)
831
+ g.sess.commit()
832
+ flash("Update successful")
833
+ return chellow_redirect(f"/dc_batch_files/{batch_file.id}", 303)
764
834
 
765
835
  except BadRequest as e:
766
836
  flash(e.description)
@@ -839,8 +909,7 @@ def dc_bill_add_post(batch_id):
839
909
  @e.route("/dc_bill_imports/<int:import_id>")
840
910
  def dc_bill_import_get(import_id):
841
911
  importer = chellow.e.bill_importer.get_bill_import(import_id)
842
- batch = Batch.get_by_id(g.sess, importer.batch_id)
843
- fields = {"batch": batch}
912
+ fields = {}
844
913
  if importer is not None:
845
914
  imp_fields = importer.make_fields()
846
915
  if "successful_bills" in imp_fields and len(imp_fields["successful_bills"]) > 0:
@@ -849,7 +918,19 @@ def dc_bill_import_get(import_id):
849
918
  )
850
919
  fields.update(imp_fields)
851
920
  fields["status"] = importer.status()
852
- return render_template("dc_bill_import.html", **fields)
921
+ if importer.batch_id is not None:
922
+ batch = Batch.get_by_id(g.sess, importer.batch_id)
923
+ return render_template(
924
+ "dc_bill_import.html", batch=batch, importer=importer, **fields
925
+ )
926
+ elif importer.contract_id is not None:
927
+ contract = Contract.get_dc_by_id(g.sess, importer.contract_id)
928
+ return render_template(
929
+ "dc_bill_import_contract.html",
930
+ contract=contract,
931
+ importer=importer,
932
+ **fields,
933
+ )
853
934
 
854
935
 
855
936
  @e.route("/dc_bills/<int:bill_id>")
@@ -926,43 +1007,53 @@ def dc_bill_edit_get(bill_id):
926
1007
  return render_template("dc_bill_edit.html", bill=bill, bill_types=bill_types)
927
1008
 
928
1009
 
1010
+ @e.route("/dc_bills/<int:bill_id>/edit", methods=["DELETE"])
1011
+ def dc_bill_edit_delete(bill_id):
1012
+ try:
1013
+ bill = Bill.get_by_id(g.sess, bill_id)
1014
+ batch = bill.batch
1015
+ bill.delete(g.sess)
1016
+ g.sess.commit()
1017
+ flash("Bill successfully deleted.")
1018
+ return hx_redirect(f"/dc_batches/{batch.id}", 303)
1019
+ except BadRequest as e:
1020
+ flash(e.description)
1021
+ bill_types = g.sess.query(BillType).order_by(BillType.code).all()
1022
+ return render_template("dc_bill_edit.html", bill=bill, bill_types=bill_types)
1023
+
1024
+
929
1025
  @e.route("/dc_bills/<int:bill_id>/edit", methods=["POST"])
930
1026
  def dc_bill_edit_post(bill_id):
931
1027
  try:
932
1028
  bill = Bill.get_by_id(g.sess, bill_id)
933
- if "delete" in request.values:
934
- bill.delete(g.sess)
935
- g.sess.commit()
936
- return chellow_redirect(f"/dc_batches/{bill.batch.id}", 303)
937
- else:
938
- account = req_str("account")
939
- reference = req_str("reference")
940
- issue_date = req_date("issue")
941
- start_date = req_date("start")
942
- finish_date = req_date("finish")
943
- kwh = req_decimal("kwh")
944
- net = req_decimal("net")
945
- vat = req_decimal("vat")
946
- gross = req_decimal("gross")
947
- type_id = req_int("bill_type_id")
948
- breakdown = req_zish("breakdown")
949
- bill_type = BillType.get_by_id(g.sess, type_id)
1029
+ account = req_str("account")
1030
+ reference = req_str("reference")
1031
+ issue_date = req_date("issue")
1032
+ start_date = req_date("start")
1033
+ finish_date = req_date("finish")
1034
+ kwh = req_decimal("kwh")
1035
+ net = req_decimal("net")
1036
+ vat = req_decimal("vat")
1037
+ gross = req_decimal("gross")
1038
+ type_id = req_int("bill_type_id")
1039
+ breakdown = req_zish("breakdown")
1040
+ bill_type = BillType.get_by_id(g.sess, type_id)
950
1041
 
951
- bill.update(
952
- account,
953
- reference,
954
- issue_date,
955
- start_date,
956
- finish_date,
957
- kwh,
958
- net,
959
- vat,
960
- gross,
961
- bill_type,
962
- breakdown,
963
- )
964
- g.sess.commit()
965
- return chellow_redirect(f"/dc_bills/{bill.id}", 303)
1042
+ bill.update(
1043
+ account,
1044
+ reference,
1045
+ issue_date,
1046
+ start_date,
1047
+ finish_date,
1048
+ kwh,
1049
+ net,
1050
+ vat,
1051
+ gross,
1052
+ bill_type,
1053
+ breakdown,
1054
+ )
1055
+ g.sess.commit()
1056
+ return chellow_redirect(f"/dc_bills/{bill.id}", 303)
966
1057
  except BadRequest as e:
967
1058
  flash(e.description)
968
1059
  bill_types = g.sess.query(BillType).order_by(BillType.code).all()
@@ -1271,6 +1362,80 @@ def dc_contracts_hh_import_get(contract_id, import_id):
1271
1362
  )
1272
1363
 
1273
1364
 
1365
+ @e.route("/dc_bills/<int:bill_id>/add_element")
1366
+ def dc_element_add_get(bill_id):
1367
+ bill = Bill.get_by_id(g.sess, bill_id)
1368
+
1369
+ return render_template("dc_element_add.html", bill=bill)
1370
+
1371
+
1372
+ @e.route("/dc_bills/<int:bill_id>/add_element", methods=["POST"])
1373
+ def dc_element_add_post(bill_id):
1374
+ try:
1375
+ bill = Bill.get_by_id(g.sess, bill_id)
1376
+ name = req_str("name")
1377
+ start_date = req_date("start")
1378
+ finish_date = req_date("finish")
1379
+ net = req_decimal("net")
1380
+ breakdown = req_zish("breakdown")
1381
+
1382
+ element = bill.insert_element(
1383
+ g.sess, name, start_date, finish_date, net, breakdown
1384
+ )
1385
+ g.sess.commit()
1386
+ return chellow_redirect(f"/dc_elements/{element.id}", 303)
1387
+ except BadRequest as e:
1388
+ flash(e.description)
1389
+ return make_response(render_template("dc_element_add.html", bill=bill), 400)
1390
+
1391
+
1392
+ @e.route("/dc_elements/<int:element_id>")
1393
+ def dc_element_get(element_id):
1394
+ element = Element.get_by_id(g.sess, element_id)
1395
+ return render_template("dc_element.html", element=element)
1396
+
1397
+
1398
+ @e.route("/dc_elements/<int:element_id>/edit")
1399
+ def dc_element_edit_get(element_id):
1400
+ element = Element.get_by_id(g.sess, element_id)
1401
+ return render_template("dc_element_edit.html", element=element)
1402
+
1403
+
1404
+ @e.route("/dc_elements/<int:element_id>/edit", methods=["POST"])
1405
+ def dc_element_edit_post(element_id):
1406
+ try:
1407
+ element = Element.get_by_id(g.sess, element_id)
1408
+ name = req_str("name")
1409
+ start_date = req_date("start")
1410
+ finish_date = req_date("finish")
1411
+ net = req_decimal("net")
1412
+ breakdown = req_zish("breakdown")
1413
+
1414
+ element.update(name, start_date, finish_date, net, breakdown)
1415
+ g.sess.commit()
1416
+ return chellow_redirect(f"/dc_elements/{element.id}", 303)
1417
+ except BadRequest as e:
1418
+ flash(e.description)
1419
+ return make_response(
1420
+ render_template("dc_element_edit.html", element=element), 400
1421
+ )
1422
+
1423
+
1424
+ @e.route("/dc_elements/<int:element_id>/edit", methods=["DELETE"])
1425
+ def dc_element_edit_delete(element_id):
1426
+ try:
1427
+ element = Element.get_by_id(g.sess, element_id)
1428
+ bill = element.bill
1429
+ element.delete(g.sess)
1430
+ g.sess.commit()
1431
+ return hx_redirect(f"/dc_bills/{bill.id}", 303)
1432
+ except BadRequest as e:
1433
+ flash(e.description)
1434
+ return make_response(
1435
+ render_template("dc_element_edit.html", element=element), 400
1436
+ )
1437
+
1438
+
1274
1439
  @e.route("/dc_contracts/<int:contract_id>/add_rate_script")
1275
1440
  def dc_rate_script_add_get(contract_id):
1276
1441
  now = utc_datetime_now()
@@ -1344,25 +1509,35 @@ def dc_rate_script_edit_get(dc_rate_script_id):
1344
1509
  )
1345
1510
 
1346
1511
 
1512
+ @e.route("/dc_rate_scripts/<int:dc_rate_script_id>/edit", methods=["DELETE"])
1513
+ def dc_rate_script_edit_delete(dc_rate_script_id):
1514
+ try:
1515
+ dc_rate_script = RateScript.get_dc_by_id(g.sess, dc_rate_script_id)
1516
+ dc_contract = dc_rate_script.contract
1517
+ dc_contract.delete_rate_script(g.sess, dc_rate_script)
1518
+ g.sess.commit()
1519
+ return hx_redirect(f"/dc_contracts/{dc_contract.id}", 303)
1520
+ except BadRequest as e:
1521
+ flash(e.description)
1522
+ return render_template(
1523
+ "dc_rate_script_edit.html", dc_rate_script=dc_rate_script
1524
+ )
1525
+
1526
+
1347
1527
  @e.route("/dc_rate_scripts/<int:dc_rate_script_id>/edit", methods=["POST"])
1348
1528
  def dc_rate_script_edit_post(dc_rate_script_id):
1349
1529
  try:
1350
1530
  dc_rate_script = RateScript.get_dc_by_id(g.sess, dc_rate_script_id)
1351
1531
  dc_contract = dc_rate_script.contract
1352
- if "delete" in request.form:
1353
- dc_contract.delete_rate_script(g.sess, dc_rate_script)
1354
- g.sess.commit()
1355
- return chellow_redirect(f"/dc_contracts/{dc_contract.id}", 303)
1356
- else:
1357
- script = req_zish("script")
1358
- start_date = req_date("start")
1359
- has_finished = req_bool("has_finished")
1360
- finish_date = req_date("finish") if has_finished else None
1361
- dc_contract.update_rate_script(
1362
- g.sess, dc_rate_script, start_date, finish_date, script
1363
- )
1364
- g.sess.commit()
1365
- return chellow_redirect(f"/dc_rate_scripts/{dc_rate_script.id}", 303)
1532
+ script = req_zish("script")
1533
+ start_date = req_date("start")
1534
+ has_finished = req_bool("has_finished")
1535
+ finish_date = req_date("finish") if has_finished else None
1536
+ dc_contract.update_rate_script(
1537
+ g.sess, dc_rate_script, start_date, finish_date, script
1538
+ )
1539
+ g.sess.commit()
1540
+ return chellow_redirect(f"/dc_rate_scripts/{dc_rate_script.id}", 303)
1366
1541
  except BadRequest as e:
1367
1542
  flash(e.description)
1368
1543
  return render_template(
@@ -2520,9 +2695,8 @@ def meter_type_get(meter_type_id):
2520
2695
  return render_template("meter_type.html", meter_type=meter_type)
2521
2696
 
2522
2697
 
2523
- @e.route("/mop_batches")
2524
- def mop_batches_get():
2525
- contract_id = req_int("mop_contract_id")
2698
+ @e.route("/mop_contracts/<int:contract_id>/batches")
2699
+ def mop_batches_get(contract_id):
2526
2700
  contract = Contract.get_mop_by_id(g.sess, contract_id)
2527
2701
  batches = g.sess.execute(
2528
2702
  select(
@@ -2540,13 +2714,35 @@ def mop_batches_get():
2540
2714
  return render_template("mop_batches.html", contract=contract, batches=batches)
2541
2715
 
2542
2716
 
2543
- @e.route("/mop_contracts/<int:contract_id>/add_batch")
2717
+ @e.route("/mop_contracts/<int:contract_id>/batches/edit")
2718
+ def mop_batches_edit_get(contract_id):
2719
+ contract = Contract.get_mop_by_id(g.sess, contract_id)
2720
+ return render_template("mop_batches_edit.html", contract=contract)
2721
+
2722
+
2723
+ @e.route("/mop_contracts/<int:contract_id>/batches/edit", methods=["POST"])
2724
+ def mop_batches_edit_post(contract_id):
2725
+ try:
2726
+ contract = Contract.get_mop_by_id(g.sess, contract_id)
2727
+ for batch in g.sess.scalars(select(Batch).where(Batch.contract == contract)):
2728
+ if len(batch.files) > 0:
2729
+ g.sess.execute(delete(Bill).where(Bill.batch == batch))
2730
+ g.sess.commit()
2731
+ import_id = chellow.e.bill_importer.start_bill_import_contract(contract)
2732
+ return hx_redirect(f"/mop_bill_imports/{import_id}")
2733
+ except BadRequest as e:
2734
+ flash(e.description)
2735
+ return make_response(
2736
+ render_template("mop_batches_edit.html", contract=contract),
2737
+ 400,
2738
+ )
2739
+
2740
+
2741
+ @e.route("/mop_contracts/<int:contract_id>/batches/add")
2544
2742
  def mop_batch_add_get(contract_id):
2545
2743
  contract = Contract.get_mop_by_id(g.sess, contract_id)
2546
- batches = (
2547
- g.sess.query(Batch)
2548
- .filter(Batch.contract == contract)
2549
- .order_by(Batch.reference.desc())
2744
+ batches = g.sess.scalars(
2745
+ select(Batch).where(Batch.contract == contract).order_by(Batch.reference.desc())
2550
2746
  )
2551
2747
  next_batch_reference, next_batch_description = contract.get_next_batch_details(
2552
2748
  g.sess
@@ -2560,7 +2756,7 @@ def mop_batch_add_get(contract_id):
2560
2756
  )
2561
2757
 
2562
2758
 
2563
- @e.route("/mop_contracts/<int:contract_id>/add_batch", methods=["POST"])
2759
+ @e.route("/mop_contracts/<int:contract_id>/batches/add", methods=["POST"])
2564
2760
  def mop_batch_add_post(contract_id):
2565
2761
  try:
2566
2762
  contract = Contract.get_mop_by_id(g.sess, contract_id)
@@ -2589,19 +2785,35 @@ def mop_batch_edit_get(batch_id):
2589
2785
  return render_template("mop_batch_edit.html", batch=batch)
2590
2786
 
2591
2787
 
2788
+ @e.route("/mop_batches/<int:batch_id>/edit", methods=["DELETE"])
2789
+ def mop_batch_edit_delete(batch_id):
2790
+ try:
2791
+ batch = Batch.get_by_id(g.sess, batch_id)
2792
+ contract = batch.contract
2793
+ batch.delete(g.sess)
2794
+ g.sess.commit()
2795
+ return hx_redirect(f"/mop_contracts/{contract.id}", 303)
2796
+ except BadRequest as e:
2797
+ flash(e.description)
2798
+ return render_template("mop_batch_edit.html", batch=batch)
2799
+
2800
+
2592
2801
  @e.route("/mop_batches/<int:batch_id>/edit", methods=["POST"])
2593
2802
  def mop_batch_edit_post(batch_id):
2594
2803
  try:
2595
2804
  batch = Batch.get_by_id(g.sess, batch_id)
2596
- if "delete" in request.values:
2597
- contract = batch.contract
2598
- batch.delete(g.sess)
2599
- g.sess.commit()
2600
- return chellow_redirect(f"/mop_contracts/{contract.id}", 303)
2601
- elif "delete_bills" in request.values:
2805
+ if "delete_bills" in request.values:
2602
2806
  g.sess.query(Bill).filter(Bill.batch_id == batch.id).delete(False)
2603
2807
  g.sess.commit()
2604
- return chellow_redirect(f"/mop_batches/{batch.id}", 303)
2808
+ return hx_redirect(f"/mop_batches/{batch.id}", 303)
2809
+ elif "import_bills" in request.values:
2810
+ import_id = chellow.e.bill_importer.start_bill_import(batch)
2811
+ return hx_redirect(f"/mop_bill_imports/{import_id}", 303)
2812
+ elif "delete_import_bills" in request.values:
2813
+ g.sess.execute(delete(Bill).where(Bill.batch == batch))
2814
+ g.sess.commit()
2815
+ import_id = chellow.e.bill_importer.start_bill_import(batch)
2816
+ return hx_redirect(f"/mop_bill_imports/{import_id}", 303)
2605
2817
  else:
2606
2818
  reference = req_str("reference")
2607
2819
  description = req_str("description")
@@ -2634,39 +2846,6 @@ def mop_batch_get(batch_id):
2634
2846
  return render_template("mop_batch.html", **fields)
2635
2847
 
2636
2848
 
2637
- @e.route("/mop_batches/<int:batch_id>", methods=["POST"])
2638
- def mop_batch_post(batch_id):
2639
- try:
2640
- batch = Batch.get_by_id(g.sess, batch_id)
2641
- if "import_bills" in request.values:
2642
- import_id = chellow.e.bill_importer.start_bill_import(batch)
2643
- return chellow_redirect(f"/mop_bill_imports/{import_id}", 303)
2644
- elif "delete_bills" in request.values:
2645
- g.sess.query(Bill).filter(Bill.batch_id == batch.id).delete(False)
2646
- g.sess.commit()
2647
- return chellow_redirect(f"/mop_batches/{batch.id}", 303)
2648
- elif "delete_import_bills" in request.values:
2649
- g.sess.query(Bill).filter(Bill.batch_id == batch.id).delete(False)
2650
- g.sess.commit()
2651
- import_id = chellow.bill_importer.start_bill_import(batch)
2652
- return chellow_redirect(f"/mop_bill_imports/{import_id}", 303)
2653
- except BadRequest as e:
2654
- flash(e.description)
2655
- importer_ids = sorted(
2656
- chellow.e.bill_importer.get_bill_import_ids(batch), reverse=True
2657
- )
2658
- parser_names = chellow.e.bill_importer.find_parser_names()
2659
- return make_response(
2660
- render_template(
2661
- "mop_batch.html",
2662
- batch=batch,
2663
- importer_ids=importer_ids,
2664
- parser_names=parser_names,
2665
- ),
2666
- 400,
2667
- )
2668
-
2669
-
2670
2849
  @e.route("/mop_batches/<int:batch_id>/csv")
2671
2850
  def mop_batch_csv_get(batch_id):
2672
2851
  batch = Batch.get_by_id(g.sess, batch_id)
@@ -2821,73 +3000,10 @@ def mop_batch_file_edit_post(file_id):
2821
3000
  @e.route("/mop_bills/<int:bill_id>")
2822
3001
  def mop_bill_get(bill_id):
2823
3002
  bill = Bill.get_by_id(g.sess, bill_id)
2824
- register_reads = (
2825
- g.sess.query(RegisterRead)
2826
- .filter(RegisterRead.bill == bill)
2827
- .order_by(RegisterRead.present_date.desc())
2828
- )
2829
- fields = {"bill": bill, "register_reads": register_reads}
2830
- try:
2831
- breakdown_dict = loads(bill.breakdown)
2832
-
2833
- raw_lines = []
2834
- for key in ("raw_lines", "raw-lines"):
2835
- try:
2836
- raw_lines += breakdown_dict[key]
2837
- del breakdown_dict[key]
2838
- except KeyError:
2839
- pass
2840
-
2841
- rows = set()
2842
- columns = set()
2843
- grid = defaultdict(dict)
2844
-
2845
- for k, v in tuple(breakdown_dict.items()):
2846
- if k.endswith("-gbp"):
2847
- columns.add("gbp")
2848
- row_name = k[:-4]
2849
- rows.add(row_name)
2850
- grid[row_name]["gbp"] = v
2851
- del breakdown_dict[k]
2852
-
2853
- for k, v in tuple(breakdown_dict.items()):
2854
- for row_name in sorted(list(rows), key=len, reverse=True):
2855
- if k.startswith(row_name + "-"):
2856
- col_name = k[len(row_name) + 1 :]
2857
- columns.add(col_name)
2858
- grid[row_name][col_name] = csv_make_val(v)
2859
- del breakdown_dict[k]
2860
- break
2861
-
2862
- for k, v in breakdown_dict.items():
2863
- pair = k.split("-")
2864
- row_name = "-".join(pair[:-1])
2865
- column_name = pair[-1]
2866
- rows.add(row_name)
2867
- columns.add(column_name)
2868
- grid[row_name][column_name] = csv_make_val(v)
2869
-
2870
- column_list = sorted(list(columns))
2871
- for rate_name in [col for col in column_list if col.endswith("rate")]:
2872
- column_list.remove(rate_name)
2873
- column_list.append(rate_name)
2874
-
2875
- if "gbp" in column_list:
2876
- column_list.remove("gbp")
2877
- column_list.append("gbp")
2878
-
2879
- row_list = sorted(list(rows))
2880
- fields.update(
2881
- {
2882
- "raw_lines": raw_lines,
2883
- "row_list": row_list,
2884
- "column_list": column_list,
2885
- "grid": grid,
2886
- }
2887
- )
2888
- except SyntaxError:
2889
- pass
2890
- return render_template("mop_bill.html", **fields)
3003
+ elements = g.sess.scalars(
3004
+ select(Element).where(Element.bill == bill).order_by(Element.start_date.desc())
3005
+ ).all()
3006
+ return render_template("mop_bill.html", bill=bill, elements=elements)
2891
3007
 
2892
3008
 
2893
3009
  @e.route("/mop_bills/<int:bill_id>/edit")
@@ -2897,43 +3013,51 @@ def mop_bill_edit_get(bill_id):
2897
3013
  return render_template("mop_bill_edit.html", bill=bill, bill_types=bill_types)
2898
3014
 
2899
3015
 
3016
+ @e.route("/mop_bills/<int:bill_id>/edit", methods=["DELETE"])
3017
+ def mop_bill_edit_delete(bill_id):
3018
+ try:
3019
+ bill = Bill.get_by_id(g.sess, bill_id)
3020
+ bill.delete(g.sess)
3021
+ g.sess.commit()
3022
+ return hx_redirect(f"/mop_batches/{bill.batch.id}", 303)
3023
+ except BadRequest as e:
3024
+ flash(e.description)
3025
+ bill_types = g.sess.query(BillType).order_by(BillType.code).all()
3026
+ return render_template("mop_bill_edit.html", bill=bill, bill_types=bill_types)
3027
+
3028
+
2900
3029
  @e.route("/mop_bills/<int:bill_id>/edit", methods=["POST"])
2901
3030
  def mop_bill_edit_post(bill_id):
2902
3031
  try:
2903
3032
  bill = Bill.get_by_id(g.sess, bill_id)
2904
- if "delete" in request.values:
2905
- bill.delete(g.sess)
2906
- g.sess.commit()
2907
- return chellow_redirect(f"/mop_batches/{bill.batch.id}", 303)
2908
- else:
2909
- account = req_str("account")
2910
- reference = req_str("reference")
2911
- issue_date = req_date("issue")
2912
- start_date = req_date("start")
2913
- finish_date = req_date("finish")
2914
- kwh = req_decimal("kwh")
2915
- net = req_decimal("net")
2916
- vat = req_decimal("vat")
2917
- gross = req_decimal("gross")
2918
- type_id = req_int("bill_type_id")
2919
- breakdown = req_zish("breakdown")
2920
- bill_type = BillType.get_by_id(g.sess, type_id)
3033
+ account = req_str("account")
3034
+ reference = req_str("reference")
3035
+ issue_date = req_date("issue")
3036
+ start_date = req_date("start")
3037
+ finish_date = req_date("finish")
3038
+ kwh = req_decimal("kwh")
3039
+ net = req_decimal("net")
3040
+ vat = req_decimal("vat")
3041
+ gross = req_decimal("gross")
3042
+ type_id = req_int("bill_type_id")
3043
+ breakdown = req_zish("breakdown")
3044
+ bill_type = BillType.get_by_id(g.sess, type_id)
2921
3045
 
2922
- bill.update(
2923
- account,
2924
- reference,
2925
- issue_date,
2926
- start_date,
2927
- finish_date,
2928
- kwh,
2929
- net,
2930
- vat,
2931
- gross,
2932
- bill_type,
2933
- breakdown,
2934
- )
2935
- g.sess.commit()
2936
- return chellow_redirect(f"/mop_bills/{bill.id}", 303)
3046
+ bill.update(
3047
+ account,
3048
+ reference,
3049
+ issue_date,
3050
+ start_date,
3051
+ finish_date,
3052
+ kwh,
3053
+ net,
3054
+ vat,
3055
+ gross,
3056
+ bill_type,
3057
+ breakdown,
3058
+ )
3059
+ g.sess.commit()
3060
+ return chellow_redirect(f"/mop_bills/{bill.id}", 303)
2937
3061
  except BadRequest as e:
2938
3062
  flash(e.description)
2939
3063
  bill_types = g.sess.query(BillType).order_by(BillType.code).all()
@@ -2943,8 +3067,7 @@ def mop_bill_edit_post(bill_id):
2943
3067
  @e.route("/mop_bill_imports/<int:import_id>")
2944
3068
  def mop_bill_import_get(import_id):
2945
3069
  importer = chellow.e.bill_importer.get_bill_import(import_id)
2946
- batch = Batch.get_by_id(g.sess, importer.batch_id)
2947
- fields = {"batch": batch}
3070
+ fields = {}
2948
3071
  if importer is not None:
2949
3072
  imp_fields = importer.make_fields()
2950
3073
  if "successful_bills" in imp_fields and len(imp_fields["successful_bills"]) > 0:
@@ -2953,7 +3076,19 @@ def mop_bill_import_get(import_id):
2953
3076
  )
2954
3077
  fields.update(imp_fields)
2955
3078
  fields["status"] = importer.status()
2956
- return render_template("mop_bill_import.html", **fields)
3079
+ if importer.batch_id is not None:
3080
+ batch = Batch.get_by_id(g.sess, importer.batch_id)
3081
+ return render_template(
3082
+ "mop_bill_import.html", batch=batch, importer=importer, **fields
3083
+ )
3084
+ elif importer.contract_id is not None:
3085
+ contract = Contract.get_mop_by_id(g.sess, importer.contract_id)
3086
+ return render_template(
3087
+ "mop_bill_import_contract.html",
3088
+ contract=contract,
3089
+ importer=importer,
3090
+ **fields,
3091
+ )
2957
3092
 
2958
3093
 
2959
3094
  @e.route("/mop_batches/<int:batch_id>/add_bill")
@@ -3100,6 +3235,80 @@ def mop_contract_edit_post(contract_id):
3100
3235
  )
3101
3236
 
3102
3237
 
3238
+ @e.route("/mop_bills/<int:bill_id>/add_element")
3239
+ def mop_element_add_get(bill_id):
3240
+ bill = Bill.get_by_id(g.sess, bill_id)
3241
+
3242
+ return render_template("mop_element_add.html", bill=bill)
3243
+
3244
+
3245
+ @e.route("/mop_bills/<int:bill_id>/add_element", methods=["POST"])
3246
+ def mop_element_add_post(bill_id):
3247
+ try:
3248
+ bill = Bill.get_by_id(g.sess, bill_id)
3249
+ name = req_str("name")
3250
+ start_date = req_date("start")
3251
+ finish_date = req_date("finish")
3252
+ net = req_decimal("net")
3253
+ breakdown = req_zish("breakdown")
3254
+
3255
+ element = bill.insert_element(
3256
+ g.sess, name, start_date, finish_date, net, breakdown
3257
+ )
3258
+ g.sess.commit()
3259
+ return chellow_redirect(f"/mop_elements/{element.id}", 303)
3260
+ except BadRequest as e:
3261
+ flash(e.description)
3262
+ return make_response(render_template("mop_element_add.html", bill=bill), 400)
3263
+
3264
+
3265
+ @e.route("/mop_elements/<int:element_id>")
3266
+ def mop_element_get(element_id):
3267
+ element = Element.get_by_id(g.sess, element_id)
3268
+ return render_template("mop_element.html", element=element)
3269
+
3270
+
3271
+ @e.route("/mop_elements/<int:element_id>/edit")
3272
+ def mop_element_edit_get(element_id):
3273
+ element = Element.get_by_id(g.sess, element_id)
3274
+ return render_template("mop_element_edit.html", element=element)
3275
+
3276
+
3277
+ @e.route("/mop_elements/<int:element_id>/edit", methods=["POST"])
3278
+ def mop_element_edit_post(element_id):
3279
+ try:
3280
+ element = Element.get_by_id(g.sess, element_id)
3281
+ name = req_str("name")
3282
+ start_date = req_date("start")
3283
+ finish_date = req_date("finish")
3284
+ net = req_decimal("net")
3285
+ breakdown = req_zish("breakdown")
3286
+
3287
+ element.update(name, start_date, finish_date, net, breakdown)
3288
+ g.sess.commit()
3289
+ return chellow_redirect(f"/mop_elements/{element.id}", 303)
3290
+ except BadRequest as e:
3291
+ flash(e.description)
3292
+ return make_response(
3293
+ render_template("mop_element_edit.html", element=element), 400
3294
+ )
3295
+
3296
+
3297
+ @e.route("/mop_elements/<int:element_id>/edit", methods=["DELETE"])
3298
+ def mop_element_edit_delete(element_id):
3299
+ try:
3300
+ element = Element.get_by_id(g.sess, element_id)
3301
+ bill = element.bill
3302
+ element.delete(g.sess)
3303
+ g.sess.commit()
3304
+ return hx_redirect(f"/mop_bills/{bill.id}", 303)
3305
+ except BadRequest as e:
3306
+ flash(e.description)
3307
+ return make_response(
3308
+ render_template("mop_element_edit.html", element=element), 400
3309
+ )
3310
+
3311
+
3103
3312
  @e.route("/mop_rate_scripts/<int:rate_script_id>")
3104
3313
  def mop_rate_script_get(rate_script_id):
3105
3314
  rate_script = RateScript.get_mop_by_id(g.sess, rate_script_id)
@@ -4831,13 +5040,11 @@ def ssc_get(ssc_id):
4831
5040
  return render_template("ssc.html", ssc=ssc)
4832
5041
 
4833
5042
 
4834
- @e.route("/supplier_contracts/<int:contract_id>/add_batch")
5043
+ @e.route("/supplier_contracts/<int:contract_id>/batches/add")
4835
5044
  def supplier_batch_add_get(contract_id):
4836
5045
  contract = Contract.get_supplier_by_id(g.sess, contract_id)
4837
- batches = (
4838
- g.sess.query(Batch)
4839
- .filter(Batch.contract == contract)
4840
- .order_by(Batch.reference.desc())
5046
+ batches = g.sess.scalars(
5047
+ select(Batch).where(Batch.contract == contract).order_by(Batch.reference.desc())
4841
5048
  )
4842
5049
  next_batch_reference, next_batch_description = contract.get_next_batch_details(
4843
5050
  g.sess
@@ -4851,7 +5058,7 @@ def supplier_batch_add_get(contract_id):
4851
5058
  )
4852
5059
 
4853
5060
 
4854
- @e.route("/supplier_contracts/<int:contract_id>/add_batch", methods=["POST"])
5061
+ @e.route("/supplier_contracts/<int:contract_id>/batches/add", methods=["POST"])
4855
5062
  def supplier_batch_add_post(contract_id):
4856
5063
  contract = Contract.get_supplier_by_id(g.sess, contract_id)
4857
5064
  try:
@@ -4865,9 +5072,9 @@ def supplier_batch_add_post(contract_id):
4865
5072
  except BadRequest as e:
4866
5073
  flash(e.description)
4867
5074
  g.sess.rollback()
4868
- batches = (
4869
- g.sess.query(Batch)
4870
- .filter(Batch.contract == contract)
5075
+ batches = g.sess.scalars(
5076
+ select(Batch)
5077
+ .where(Batch.contract == contract)
4871
5078
  .order_by(Batch.reference.desc())
4872
5079
  )
4873
5080
  return make_response(
@@ -4878,10 +5085,12 @@ def supplier_batch_add_post(contract_id):
4878
5085
  )
4879
5086
 
4880
5087
 
4881
- @e.route("/supplier_batches")
4882
- def supplier_batches_get():
4883
- contract_id = req_int("supplier_contract_id")
5088
+ @e.route("/supplier_contracts/<int:contract_id>/batches")
5089
+ def supplier_batches_get(contract_id):
4884
5090
  contract = Contract.get_supplier_by_id(g.sess, contract_id)
5091
+ importer_ids = sorted(
5092
+ chellow.e.bill_importer.get_bill_import_ids_contract(contract), reverse=True
5093
+ )
4885
5094
  batches = g.sess.execute(
4886
5095
  select(
4887
5096
  Batch,
@@ -4896,7 +5105,36 @@ def supplier_batches_get():
4896
5105
  .group_by(Batch.id)
4897
5106
  .order_by(Batch.reference.desc())
4898
5107
  )
4899
- return render_template("supplier_batches.html", contract=contract, batches=batches)
5108
+ return render_template(
5109
+ "supplier_batches.html",
5110
+ contract=contract,
5111
+ batches=batches,
5112
+ importer_ids=importer_ids,
5113
+ )
5114
+
5115
+
5116
+ @e.route("/supplier_contracts/<int:contract_id>/batches/edit")
5117
+ def supplier_batches_edit_get(contract_id):
5118
+ contract = Contract.get_supplier_by_id(g.sess, contract_id)
5119
+ return render_template("supplier_batches_edit.html", contract=contract)
5120
+
5121
+
5122
+ @e.route("/supplier_contracts/<int:contract_id>/batches/edit", methods=["POST"])
5123
+ def supplier_batches_edit_post(contract_id):
5124
+ try:
5125
+ contract = Contract.get_supplier_by_id(g.sess, contract_id)
5126
+ for batch in g.sess.scalars(select(Batch).where(Batch.contract == contract)):
5127
+ if len(batch.files) > 0:
5128
+ g.sess.execute(delete(Bill).where(Bill.batch == batch))
5129
+ g.sess.commit()
5130
+ import_id = chellow.e.bill_importer.start_bill_import_contract(contract)
5131
+ return hx_redirect(f"/supplier_bill_imports/{import_id}")
5132
+ except BadRequest as e:
5133
+ flash(e.description)
5134
+ return make_response(
5135
+ render_template("supplier_batches_edit.html", contract=contract),
5136
+ 400,
5137
+ )
4900
5138
 
4901
5139
 
4902
5140
  @e.route("/supplier_batches/<int:batch_id>")
@@ -5030,7 +5268,7 @@ def supplier_batch_post(batch_id):
5030
5268
  g.sess.commit()
5031
5269
  return hx_redirect(f"/supplier_batches/{batch.id}")
5032
5270
  elif "delete_import_bills" in request.values:
5033
- g.sess.query(Bill).filter(Bill.batch_id == batch.id).delete(False)
5271
+ g.sess.execute(delete(Bill).where(Bill.batch == batch))
5034
5272
  g.sess.commit()
5035
5273
  import_id = chellow.e.bill_importer.start_bill_import(batch)
5036
5274
  return hx_redirect(f"/supplier_bill_imports/{import_id}")
@@ -5274,7 +5512,6 @@ def supplier_bill_add_post(batch_id):
5274
5512
  @e.route("/supplier_bill_imports/<int:import_id>")
5275
5513
  def supplier_bill_import_get(import_id):
5276
5514
  importer = chellow.e.bill_importer.get_bill_import(import_id)
5277
- batch = Batch.get_by_id(g.sess, importer.batch_id)
5278
5515
  fields = {}
5279
5516
  if importer is not None:
5280
5517
  imp_fields = importer.make_fields()
@@ -5288,23 +5525,33 @@ def supplier_bill_import_get(import_id):
5288
5525
  )
5289
5526
  fields.update(imp_fields)
5290
5527
  fields["status"] = importer.status()
5291
- return render_template(
5292
- "supplier_bill_import.html", batch=batch, importer=importer, **fields
5293
- )
5528
+
5529
+ if importer.batch_id is not None:
5530
+ batch = Batch.get_by_id(g.sess, importer.batch_id)
5531
+ return render_template(
5532
+ "supplier_bill_import.html", batch=batch, importer=importer, **fields
5533
+ )
5534
+ elif importer.contract_id is not None:
5535
+ contract = Contract.get_supplier_by_id(g.sess, importer.contract_id)
5536
+ return render_template(
5537
+ "supplier_bill_import_contract.html",
5538
+ contract=contract,
5539
+ importer=importer,
5540
+ **fields,
5541
+ )
5294
5542
 
5295
5543
 
5296
5544
  @e.route("/supplier_bills/<int:bill_id>")
5297
5545
  def supplier_bill_get(bill_id):
5298
5546
  bill = Bill.get_by_id(g.sess, bill_id)
5299
- register_reads = (
5300
- g.sess.query(RegisterRead)
5301
- .filter(RegisterRead.bill == bill)
5547
+ register_reads = g.sess.scalars(
5548
+ select(RegisterRead)
5549
+ .where(RegisterRead.bill == bill)
5302
5550
  .order_by(RegisterRead.present_date.desc())
5303
5551
  )
5304
5552
 
5305
- rate_scripts = (
5306
- g.sess.query(RateScript)
5307
- .filter(
5553
+ rate_scripts = g.sess.scalars(
5554
+ select(RateScript).where(
5308
5555
  RateScript.contract == bill.batch.contract,
5309
5556
  RateScript.start_date <= bill.finish_date,
5310
5557
  or_(
@@ -5312,12 +5559,15 @@ def supplier_bill_get(bill_id):
5312
5559
  RateScript.finish_date >= bill.start_date,
5313
5560
  ),
5314
5561
  )
5315
- .all()
5562
+ ).all()
5563
+ elements = g.sess.scalars(
5564
+ select(Element).where(Element.bill == bill).order_by(Element.name)
5316
5565
  )
5317
5566
  fields = {
5318
5567
  "bill": bill,
5319
5568
  "register_reads": register_reads,
5320
5569
  "rate_scripts": rate_scripts,
5570
+ "elements": elements,
5321
5571
  }
5322
5572
  try:
5323
5573
  breakdown_dict = loads(bill.breakdown)
@@ -5455,44 +5705,139 @@ def supplier_contract_edit_get(contract_id):
5455
5705
  )
5456
5706
 
5457
5707
 
5708
+ @e.route("/supplier_contracts/<int:contract_id>/edit", methods=["DELETE"])
5709
+ def supplier_contract_edit_delete(contract_id):
5710
+ try:
5711
+ contract = Contract.get_supplier_by_id(g.sess, contract_id)
5712
+ contract.delete(g.sess)
5713
+ g.sess.commit()
5714
+ return chellow_redirect("/supplier_contracts", 303)
5715
+ except BadRequest as e:
5716
+ g.sess.rollback()
5717
+ description = e.description
5718
+ flash(description)
5719
+ parties = (
5720
+ g.sess.query(Party)
5721
+ .join(MarketRole)
5722
+ .join(Participant)
5723
+ .filter(MarketRole.code == "X")
5724
+ .order_by(Participant.code)
5725
+ .all()
5726
+ )
5727
+ return make_response(
5728
+ render_template(
5729
+ "supplier_contract_edit.html", contract=contract, parties=parties
5730
+ ),
5731
+ 400,
5732
+ )
5733
+
5734
+
5458
5735
  @e.route("/supplier_contracts/<int:contract_id>/edit", methods=["POST"])
5459
5736
  def supplier_contract_edit_post(contract_id):
5460
5737
  try:
5461
5738
  contract = Contract.get_supplier_by_id(g.sess, contract_id)
5462
- if "delete" in request.form:
5463
- contract.delete(g.sess)
5464
- g.sess.commit()
5465
- return chellow_redirect("/supplier_contracts", 303)
5466
- else:
5467
- party_id = req_int("party_id")
5468
- party = Party.get_by_id(g.sess, party_id)
5469
- name = req_str("name")
5470
- charge_script = req_str("charge_script")
5471
- properties = req_zish("properties")
5472
- contract.update(name, party, charge_script, properties)
5473
- g.sess.commit()
5474
- return chellow_redirect(f"/supplier_contracts/{contract.id}", 303)
5739
+ party_id = req_int("party_id")
5740
+ party = Party.get_by_id(g.sess, party_id)
5741
+ name = req_str("name")
5742
+ charge_script = req_str("charge_script")
5743
+ properties = req_zish("properties")
5744
+ contract.update(name, party, charge_script, properties)
5745
+ g.sess.commit()
5746
+ return chellow_redirect(f"/supplier_contracts/{contract.id}", 303)
5475
5747
  except BadRequest as e:
5476
5748
  g.sess.rollback()
5477
5749
  description = e.description
5478
5750
  flash(description)
5479
- if description.startswith("There isn't a contract"):
5480
- raise
5481
- else:
5482
- parties = (
5483
- g.sess.query(Party)
5484
- .join(MarketRole)
5485
- .join(Participant)
5486
- .filter(MarketRole.code == "X")
5487
- .order_by(Participant.code)
5488
- .all()
5489
- )
5490
- return make_response(
5491
- render_template(
5492
- "supplier_contract_edit.html", contract=contract, parties=parties
5493
- ),
5494
- 400,
5495
- )
5751
+ parties = (
5752
+ g.sess.query(Party)
5753
+ .join(MarketRole)
5754
+ .join(Participant)
5755
+ .filter(MarketRole.code == "X")
5756
+ .order_by(Participant.code)
5757
+ .all()
5758
+ )
5759
+ return make_response(
5760
+ render_template(
5761
+ "supplier_contract_edit.html", contract=contract, parties=parties
5762
+ ),
5763
+ 400,
5764
+ )
5765
+
5766
+
5767
+ @e.route("/supplier_bills/<int:bill_id>/add_element")
5768
+ def supplier_element_add_get(bill_id):
5769
+ bill = Bill.get_by_id(g.sess, bill_id)
5770
+
5771
+ return render_template("supplier_element_add.html", bill=bill)
5772
+
5773
+
5774
+ @e.route("/supplier_bills/<int:bill_id>/add_element", methods=["POST"])
5775
+ def supplier_element_add_post(bill_id):
5776
+ try:
5777
+ bill = Bill.get_by_id(g.sess, bill_id)
5778
+ name = req_str("name")
5779
+ start_date = req_date("start")
5780
+ finish_date = req_date("finish")
5781
+ net = req_decimal("net")
5782
+ breakdown = req_zish("breakdown")
5783
+
5784
+ element = bill.insert_element(
5785
+ g.sess, name, start_date, finish_date, net, breakdown
5786
+ )
5787
+ g.sess.commit()
5788
+ return chellow_redirect(f"/supplier_elements/{element.id}", 303)
5789
+ except BadRequest as e:
5790
+ flash(e.description)
5791
+ return make_response(
5792
+ render_template("supplier_element_add.html", bill=bill), 400
5793
+ )
5794
+
5795
+
5796
+ @e.route("/supplier_elements/<int:element_id>")
5797
+ def supplier_element_get(element_id):
5798
+ element = Element.get_by_id(g.sess, element_id)
5799
+ return render_template("supplier_element.html", element=element)
5800
+
5801
+
5802
+ @e.route("/supplier_elements/<int:element_id>/edit")
5803
+ def supplier_element_edit_get(element_id):
5804
+ element = Element.get_by_id(g.sess, element_id)
5805
+ return render_template("supplier_element_edit.html", element=element)
5806
+
5807
+
5808
+ @e.route("/supplier_elements/<int:element_id>/edit", methods=["POST"])
5809
+ def supplier_element_edit_post(element_id):
5810
+ try:
5811
+ element = Element.get_by_id(g.sess, element_id)
5812
+ name = req_str("name")
5813
+ start_date = req_date("start")
5814
+ finish_date = req_date("finish")
5815
+ net = req_decimal("net")
5816
+ breakdown = req_zish("breakdown")
5817
+
5818
+ element.update(name, start_date, finish_date, net, breakdown)
5819
+ g.sess.commit()
5820
+ return chellow_redirect(f"/supplier_elements/{element.id}", 303)
5821
+ except BadRequest as e:
5822
+ flash(e.description)
5823
+ return make_response(
5824
+ render_template("supplier_element_edit.html", element=element), 400
5825
+ )
5826
+
5827
+
5828
+ @e.route("/supplier_elements/<int:element_id>/edit", methods=["DELETE"])
5829
+ def supplier_element_edit_delete(element_id):
5830
+ try:
5831
+ element = Element.get_by_id(g.sess, element_id)
5832
+ bill = element.bill
5833
+ element.delete(g.sess)
5834
+ g.sess.commit()
5835
+ return hx_redirect(f"/supplier_bills/{bill.id}", 303)
5836
+ except BadRequest as e:
5837
+ flash(e.description)
5838
+ return make_response(
5839
+ render_template("supplier_element_edit.html", element=element), 400
5840
+ )
5496
5841
 
5497
5842
 
5498
5843
  @e.route("/supplier_rate_scripts/<int:rate_script_id>")