diff --git a/README.md b/README.md index c5169da..316c4e1 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,9 @@ This repository stores structured truck freight forwarding records for future an Files - truck_freight_ledger.json: canonical structured ledger +- truck_freight_ledger.csv: spreadsheet-friendly export +- truck_freight_summary.md: quick human-readable summary +- append_load.py: helper to append a new record and regenerate exports Schema notes - currency: currency code @@ -26,3 +29,5 @@ Usage - Append new loads as new records. - Keep corrections in notes when the user updates details. - Use the JSON file for future AI analysis and profit/pending calculations. +- Use append_load.py to add a new record and automatically regenerate the CSV and summary files. + diff --git a/append_load.py b/append_load.py new file mode 100755 index 0000000..52cd250 --- /dev/null +++ b/append_load.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +"""Append a new freight record and regenerate CSV/summary outputs. + +Usage: + python3 append_load.py new_record.json + +The input JSON should be a single record object with fields matching the ledger schema. +""" +import csv +import json +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parent +LEDGER_PATH = ROOT / 'truck_freight_ledger.json' +CSV_PATH = ROOT / 'truck_freight_ledger.csv' +SUMMARY_PATH = ROOT / 'truck_freight_summary.md' + +FIELDNAMES = [ + 'id','date','status','vehicle','from','via','to','shipper','load_type','item','deliveries', + 'freight_charged','advance_received','paid_to_driver','commission','driver_freight', + 'pending_from_shipper','pending_to_driver','notes' +] + + +def join_list(v): + if v is None: + return '' + if isinstance(v, list): + return ' | '.join(str(x) for x in v) + return str(v) + + +def load_ledger(): + return json.loads(LEDGER_PATH.read_text()) + + +def write_csv(records): + with CSV_PATH.open('w', newline='') as f: + writer = csv.DictWriter(f, fieldnames=FIELDNAMES) + writer.writeheader() + for r in records: + row = {k: '' for k in FIELDNAMES} + for k in ['id','date','status','vehicle','from','to','shipper','load_type','item','freight_charged','advance_received','paid_to_driver','commission','driver_freight','pending_from_shipper','pending_to_driver','notes']: + row[k] = r.get(k, '') if r.get(k, '') is not None else '' + row['via'] = join_list(r.get('via')) + row['deliveries'] = join_list(r.get('deliveries')) + writer.writerow(row) + + +def write_summary(records): + def total(key): + s = 0 + for r in records: + v = r.get(key) + if isinstance(v, (int, float)): + s += v + return s + + num_records = len(records) + settled = sum(1 for r in records if r.get('status') == 'settled') + pending_or_partial = sum(1 for r in records if 'pending' in (r.get('status') or '') or r.get('status') == 'partial') + + lines = [] + lines.append('# Truck Freight Ledger Summary') + lines.append('') + lines.append('Overview') + lines.append(f'- Records: {num_records}') + lines.append(f'- Settled loads: {settled}') + lines.append(f'- Pending/partial loads: {pending_or_partial}') + lines.append('') + lines.append('Totals') + lines.append(f'- Freight charged: {total("freight_charged")}') + lines.append(f'- Advance received: {total("advance_received")}') + lines.append(f'- Paid to driver: {total("paid_to_driver")}') + lines.append(f'- Commission: {total("commission")}') + lines.append(f'- Pending from shipper: {total("pending_from_shipper")}') + lines.append(f'- Pending to driver: {total("pending_to_driver")}') + lines.append('') + lines.append('Record snapshot') + lines.append('| Date | Vehicle | Shipper | Route | Freight | Advance | Paid driver | Commission | Pending shipper | Status |') + lines.append('|---|---|---|---|---:|---:|---:|---:|---:|---|') + for r in sorted(records, key=lambda x: (x.get('date') or '', x.get('vehicle') or '', x.get('id') or '')): + route = ' → '.join([p for p in [r.get('from'), r.get('to')] if p]) + if r.get('via'): + route = f"{r.get('from')} via {join_list(r.get('via'))} → {r.get('to')}" + lines.append( + f"| {r.get('date','')} | {r.get('vehicle','') or '-'} | {r.get('shipper','') or '-'} | {route or '-'} | {r.get('freight_charged','') if r.get('freight_charged') is not None else '-'} | {r.get('advance_received','') if r.get('advance_received') is not None else '-'} | {r.get('paid_to_driver','') if r.get('paid_to_driver') is not None else '-'} | {r.get('commission','') if r.get('commission') is not None else '-'} | {r.get('pending_from_shipper','') if r.get('pending_from_shipper') is not None else '-'} | {r.get('status','') or '-'} |" + ) + SUMMARY_PATH.write_text('\n'.join(lines) + '\n') + + +def main(): + if len(sys.argv) != 2: + print('Usage: python3 append_load.py new_record.json', file=sys.stderr) + raise SystemExit(2) + new_record = json.loads(Path(sys.argv[1]).read_text()) + ledger = load_ledger() + ledger.setdefault('records', []).append(new_record) + ledger['records'] = sorted(ledger['records'], key=lambda x: (x.get('date') or '', x.get('vehicle') or '', x.get('id') or '')) + LEDGER_PATH.write_text(json.dumps(ledger, indent=2, ensure_ascii=False) + '\n') + write_csv(ledger['records']) + write_summary(ledger['records']) + print(f"Appended record {new_record.get('id', '(no id)')} and regenerated CSV + summary.") + + +if __name__ == '__main__': + main() diff --git a/truck_freight_ledger.csv b/truck_freight_ledger.csv new file mode 100644 index 0000000..9f0369c --- /dev/null +++ b/truck_freight_ledger.csv @@ -0,0 +1,13 @@ +id,date,status,vehicle,from,via,to,shipper,load_type,item,deliveries,freight_charged,advance_received,paid_to_driver,commission,driver_freight,pending_from_shipper,pending_to_driver,notes +2026-05-17-jinu-coin-trivandrum-shabarimala-chennai,2026-05-17,partial,,Trivandrum,Shabarimala,Chennai,Jinu Coin,,,,,,,,,,,"User first said shipper was Minutes Coin, then corrected to Jinu Coin. No amounts were provided." +2026-05-17-ka04ag7476-drs-agarwal,2026-05-17,pending collection,KA04AG7476,Thiruvananthapuram,,Mysore,DRS Agarwal,Household,,,16500,14500,14000,0,,2000,0,User said DRS paid 14500 advance. User paid driver 10000 advance and 4000 balance. Later user clarified DRS was charged 16500 and 2000 is still due. +2026-05-17-ka04ag7476-krs-partload,2026-05-17,handled directly by shipper,KA04AG7476,Kollam,,Bangalore,KRS,,MG car battery,,11000,5000,,,,6000,0,KRS handled payment directly. Driver received 5000 advance from KRS and 6000 on delivery. User said this part-load does not create pending for them. +2026-05-17-hr38ac0945-agarwal-packers-movers,2026-05-17,pending collection,HR38AC0945,Trivandrum,,Chennai,Agarwal Packers and Movers,,,,19500,15000,15000,,,4500,0,Manager Vikas paid driver 15000 as advance. Balance of 4500 was pending. +2026-05-15-tn25ca9552-century-polymers,2026-05-15,commission received,TN25CA9552,Kollam,,Chennai,Century Polymers,,,Ambattur | Madhavaram,18000,,,1000,,,,Payment managed by Century Polymers. User received 1000 cash commission from driver. +2026-05-15-tn41dc5854-chips,2026-05-15,commission due,TN41DC5854,Thiruvananthapuram,,Palakkad,Chips,,,,11000,,,600,,,,User said commission due is 600. +2026-05-14-kl07bp2609-sahara-packers,2026-05-14,settled,KL07BP2609,Adoor,,Cochin,Sahara Packers,,,,7000,7000,6500,500,,0,0,"User clarified Sahara paid 7000 total, user paid 5500 advance and 1000 balance to truck, leaving 500 profit." +2026-05-14-ka06ba2739-agarwal,2026-05-14,fully pending from shipper,KA06BA2739,Thiruvananthapuram,,Hyderabad,Agarwal,,,,38000,0,33500,,,38000,4500,User said they did not receive any payment from Agarwal for this load. User paid driver 30000 and 3500. +2026-05-15-tn37bs7431-ambika-packers,2026-05-15,partially pending,TN37BS7431,Thiruvananthapuram,,Thrissur,Ambika Packers,,,,5500,5000,5000,500,,500,500,User said 500 will be their commission. There is also 500 still due from the shipper based on the numbers given. +2026-05-13-tn48bd4858-agarwal-packers-movers,2026-05-13,settled,TN48BD4858,Thiruvananthapuram,,Thirupathy,Agarwal Packers and Movers,,,,23000,23000,21700,1300,,0,0,"User later confirmed the pending 2000 was also paid, so the load is settled." +2026-05-17-ka63a7003-indian-cbe-shipper,2026-05-17,partially pending,KA63A7003,Thiruvananthapuram,,Coimbatore,Indian CBE Shipper,,,,7000,6500,5000,500,6000,500,500,"User said they received 6500 advance, paid 5000, and will charge the driver another 500 as commission." +2026-05-12-mh48dc1206-agarwal-packers-movers,2026-05-12,reconciled,MH48DC1206,Trivandrum,,Mumbai,Agarwal Packers and Movers,,,,41000,38000,40000,2000,,3000,0,"User first shared total 41000, advance 38000, balance 3000. Later clarified they received 38000, paid 20000 + 15000, and the driver freight was 40000 with 2000 commission." diff --git a/truck_freight_summary.md b/truck_freight_summary.md new file mode 100644 index 0000000..6cf9c58 --- /dev/null +++ b/truck_freight_summary.md @@ -0,0 +1,30 @@ +# Truck Freight Ledger Summary + +Overview +- Records: 12 +- Settled loads: 2 +- Pending/partial loads: 10 + +Totals +- Freight charged: 197500 +- Advance received: 114000 +- Paid to driver: 140700 +- Commission: 6400 +- Pending from shipper: 54500 +- Pending to driver: 5500 + +Record snapshot +| Date | Vehicle | Shipper | Route | Freight | Advance | Paid driver | Commission | Pending shipper | Status | +|---|---|---|---|---:|---:|---:|---:|---:|---| +| 2026-05-12 | MH48DC1206 | Agarwal Packers and Movers | Trivandrum → Mumbai | 41000 | 38000 | 40000 | 2000 | 3000 | reconciled | +| 2026-05-13 | TN48BD4858 | Agarwal Packers and Movers | Thiruvananthapuram → Thirupathy | 23000 | 23000 | 21700 | 1300 | 0 | settled | +| 2026-05-14 | KA06BA2739 | Agarwal | Thiruvananthapuram → Hyderabad | 38000 | 0 | 33500 | - | 38000 | fully pending from shipper | +| 2026-05-14 | KL07BP2609 | Sahara Packers | Adoor → Cochin | 7000 | 7000 | 6500 | 500 | 0 | settled | +| 2026-05-15 | TN25CA9552 | Century Polymers | Kollam → Chennai | 18000 | - | - | 1000 | - | commission received | +| 2026-05-15 | TN37BS7431 | Ambika Packers | Thiruvananthapuram → Thrissur | 5500 | 5000 | 5000 | 500 | 500 | partially pending | +| 2026-05-15 | TN41DC5854 | Chips | Thiruvananthapuram → Palakkad | 11000 | - | - | 600 | - | commission due | +| 2026-05-17 | - | Jinu Coin | Trivandrum via Shabarimala → Chennai | - | - | - | - | - | partial | +| 2026-05-17 | HR38AC0945 | Agarwal Packers and Movers | Trivandrum → Chennai | 19500 | 15000 | 15000 | - | 4500 | pending collection | +| 2026-05-17 | KA04AG7476 | DRS Agarwal | Thiruvananthapuram → Mysore | 16500 | 14500 | 14000 | 0 | 2000 | pending collection | +| 2026-05-17 | KA04AG7476 | KRS | Kollam → Bangalore | 11000 | 5000 | - | - | 6000 | handled directly by shipper | +| 2026-05-17 | KA63A7003 | Indian CBE Shipper | Thiruvananthapuram → Coimbatore | 7000 | 6500 | 5000 | 500 | 500 | partially pending |