Initial commit - Selenium automation framework

This commit is contained in:
2026-09-08 09:24:02 +05:30
commit e84b7e9950
76 changed files with 7484 additions and 0 deletions
+393
View File
@@ -0,0 +1,393 @@
"""
generate_bid_json.py
====================
Bulk JSON generator for bid submission payloads.
FOLDER STRUCTURE (input_root):
input_root/
<segment>/ e.g. GDAM | DAM | HPDAM
<order_type>/ e.g. Single | Block
<order_side>/ e.g. Buy | Sell
<TM_folder>/ e.g. C1001 → becomes userId AND tmId
<tacId>.xlsx ← one file per TAC / bid sheet
SEGMENT → JSON "segment" MAPPING:
GDAM → "GREEN"
DAM → "CONVENTIONAL"
HPDAM → "HPDAM"
SEGMENT → JSON order "source" MAPPING:
GDAM → "SL"
DAM → "CO"
HPDAM → "HP"
ORDER SIDE → JSON "orderSide" MAPPING:
Buy → "B"
Sell → "S"
ORDER TYPE → JSON "orderType" MAPPING:
Single → "N"
Block → "B"
EXCEL LAYOUT (every .xlsx):
Row 1 : "Select Source" | "Order 1" | "Order 2" ... "Order N"
Row 2 : "<label>" | <price1> | <price2> ... <priceN>
Row 3+: "HH:MM-HH:MM [slot]" | <qty1> | <qty2> ...
(rows where ALL qty cells are blank are skipped)
OUTPUT:
output_root/
<segment>/
<order_type>/
<order_side>/
<TM_folder>/
<tacId>_bid.json
CONFIGURABLE via CLI (or edit DEFAULTS below):
--input_root path to input folder tree
--output_root path where JSON tree is written
--product_code e.g. "IDAS(01)"
--password password applied to every payload
--ocf_opted Y or N
--ocf_premium_disc integer
--ocf_qty integer
FIXED / AUTO-DERIVED:
transcode = "3040" (always)
requestType = "N" (always)
productType = "I" (always)
userId = TM folder name
tmId = TM folder name
segment = derived from segment folder name (see mapping above)
orderSide = derived from order_side folder name
orderType = derived from order_type folder name
deliveryDate = tomorrow's date (auto-calculated at run time)
USAGE:
python generate_bid_json.py \\
--input_root ./input \\
--output_root ./output \\
--product_code "IDAS(01)" \\
--password "your_password"
Or just edit DEFAULTS below and run:
python generate_bid_json.py
"""
import argparse
import json
import re
import sys
from datetime import date, timedelta
from pathlib import Path
from openpyxl import load_workbook
# ─────────────────────────────────────────────────────────────────────────────
# DEFAULTS – edit here or override via CLI
# ─────────────────────────────────────────────────────────────────────────────
DEFAULTS = {
"input_root": "D:/Load testing input json/Input scenario upload files",
"output_root": "D:/Load testing input json/UAT_Team_10%_Load_File",
"product_code": "IDASTEST25",
"password": "CHANGE_ME",
"ocf_opted": "N",
"ocf_premium_disc": 0,
"ocf_qty": 0,
}
# ─────────────────────────────────────────────────────────────────────────────
# FIXED CONSTANTS
# ─────────────────────────────────────────────────────────────────────────────
TRANSCODE = "3040"
REQUEST_TYPE = "N"
PRODUCT_TYPE = "I"
# Segment folder name → JSON segment value
SEGMENT_MAP = {
"GDAM": "GREEN",
"DAM": "Conventional",
"HPDAM": "HPDAM",
}
# Order-type folder name → JSON orderType value
ORDER_TYPE_MAP = {
"Single": "N",
"Block": "B",
}
# Order-side folder name → JSON orderSide value
ORDER_SIDE_MAP = {
"Buy": "B",
"Sell": "S",
}
# Segment folder name → JSON order "source" value
SOURCE_MAP = {
"GDAM": "SL",
"DAM": "CO",
"HPDAM": "HP",
}
# ─────────────────────────────────────────────────────────────────────────────
# HELPERS
# ─────────────────────────────────────────────────────────────────────────────
def tomorrow_str() -> str:
"""Return tomorrow's date as 'DD-Mon-YYYY', e.g. '18-Jun-2026'."""
d = date.today() + timedelta(days=1)
# %-d is Linux-only; %#d is Windows-only — use manual strip for cross-platform
return d.strftime("%d-%b-%Y").lstrip("0")
def parse_excel(xlsx_path: Path, order_type_val: str, order_side_val: str, source_val: str, seg_folder: str, cfg: dict) -> list[dict]:
"""
Parse one bid Excel file and return a list of order dicts.
tacId is the filename stem (e.g. 'MCOC100500002').
"""
wb = load_workbook(str(xlsx_path), read_only=True, data_only=True)
ws = wb.active
rows = list(ws.iter_rows(values_only=True))
if len(rows) < 3:
raise ValueError(f"File has fewer than 3 rows: {xlsx_path}")
# Row 2 (index 1): price row
price_row = rows[1]
prices = []
for cell in price_row[1:]:
if cell is None or cell == "":
break
prices.append(int(round(float(cell))))
if not prices:
raise ValueError(f"No price columns found in row 2 of: {xlsx_path}")
tac_id = xlsx_path.stem
orders = []
for row in rows[2:]:
label = row[0]
if not label:
continue
match = re.search(r'\[(\d+)\]', str(label))
if not match:
continue
slot_num = int(match.group(1))
qtys = []
for i in range(len(prices)):
raw = row[i + 1] if (i + 1) < len(row) else None
qtys.append(round(abs(float(raw)), 4) if (raw is not None and raw != "") else None)
# Skip slots where every qty cell is blank
if all(q is None for q in qtys):
continue
pq_data = [
{"price": price, "qty": qty}
for price, qty in zip(prices, qtys)
if qty is not None
]
order = {
"tacId": tac_id,
"fromSlot": slot_num,
"toSlot": slot_num,
"orderType": order_type_val,
"orderSide": order_side_val,
"source": source_val,
"sourceType": "",
}
# OCF fields are excluded for HPDAM segment
if seg_folder != "HPDAM":
order["ocfOpted"] = cfg["ocf_opted"]
order["ocfPremiumDisc"] = cfg["ocf_premium_disc"]
order["ocfQty"] = cfg["ocf_qty"]
order["pqData"] = pq_data
orders.append(order)
return orders
def build_payload(tm_id: str, segment_val: str, orders: list[dict], cfg: dict) -> dict:
return {
"transcode": TRANSCODE,
"userId": tm_id,
"password": cfg["password"],
"tmId": tm_id,
"requestType": REQUEST_TYPE,
"productCode": cfg["product_code"],
"productType": PRODUCT_TYPE,
"segment": segment_val,
"deliveryDate": tomorrow_str(),
"orders": orders,
}
# ─────────────────────────────────────────────────────────────────────────────
# MAIN WALK
# ─────────────────────────────────────────────────────────────────────────────
def process_all(cfg: dict):
input_root = Path(cfg["input_root"])
output_root = Path(cfg["output_root"])
if not input_root.exists():
print(f"[ERROR] input_root not found: {input_root}", file=sys.stderr)
sys.exit(1)
total_files = 0
total_errors = 0
print(f"Delivery date (tomorrow): {tomorrow_str()}")
print(f"Input : {input_root.resolve()}")
print(f"Output : {output_root.resolve()}")
print("-" * 72)
# ── Level 1: segment folder (GDAM / DAM / HPDAM) ─────────────────────────
for seg_dir in sorted(input_root.iterdir()):
if not seg_dir.is_dir() or seg_dir.name.startswith("."):
continue
seg_folder = seg_dir.name
segment_val = SEGMENT_MAP.get(seg_folder)
if segment_val is None:
print(f"[WARN] Unknown segment folder '{seg_folder}' — skipping.")
continue
source_val = SOURCE_MAP[seg_folder] # guaranteed present since SEGMENT_MAP check passed
# ── Level 2: order type folder (Single / Block) ───────────────────────
for ot_dir in sorted(seg_dir.iterdir()):
if not ot_dir.is_dir():
continue
ot_folder = ot_dir.name
if ot_folder == "Block":
print(f" [SKIP] Block order-type folder ignored: {ot_dir.relative_to(input_root)}")
continue
order_type_val = ORDER_TYPE_MAP.get(ot_folder)
if order_type_val is None:
print(f"[WARN] Unknown order-type folder '{ot_folder}' — skipping.")
continue
# ── Level 3: order side folder (Buy / Sell) ───────────────────────
for os_dir in sorted(ot_dir.iterdir()):
if not os_dir.is_dir():
continue
os_folder = os_dir.name
order_side_val = ORDER_SIDE_MAP.get(os_folder)
if order_side_val is None:
print(f"[WARN] Unknown order-side folder '{os_folder}' — skipping.")
continue
# Fix 2: source is blank for Buy orders, segment-mapped only for Sell
effective_source = "" if os_folder == "Buy" else source_val
# ── Level 4: TM folder (e.g. C1001) ──────────────────────────
for tm_dir in sorted(os_dir.iterdir()):
if not tm_dir.is_dir():
continue
tm_id = tm_dir.name # → userId AND tmId
# ── Level 5: xlsx files ───────────────────────────────────
for xlsx_file in sorted(tm_dir.glob("*.xlsx")):
total_files += 1
rel_path = xlsx_file.relative_to(input_root)
print(f" {rel_path}", end=" ... ")
try:
orders = parse_excel(
xlsx_file,
order_type_val=order_type_val,
order_side_val=order_side_val,
source_val=effective_source,
seg_folder=seg_folder,
cfg=cfg,
)
payload = build_payload(
tm_id=tm_id,
segment_val=segment_val,
orders=orders,
cfg=cfg,
)
# Output lands directly in output_root/<segment>/
out_dir = output_root / seg_folder
out_dir.mkdir(parents=True, exist_ok=True)
out_file = out_dir / f"{xlsx_file.stem}_bid.json"
with open(out_file, "w") as f:
json.dump(payload, f, indent=4)
print(f"OK → {out_file.relative_to(output_root)} ({len(orders)} orders)")
except Exception as exc:
print(f"FAILED — {exc}", file=sys.stderr)
total_errors += 1
print("-" * 72)
print(f"Done. {total_files} file(s) processed, {total_errors} error(s).")
# ─────────────────────────────────────────────────────────────────────────────
# CLI
# ─────────────────────────────────────────────────────────────────────────────
def main():
parser = argparse.ArgumentParser(
description="Bulk-generate bid JSON files from Excel bid sheets.",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Folder structure expected under --input_root:
<segment>/ GDAM | DAM | HPDAM
<order_type>/ Single | Block
<order_side>/ Buy | Sell
<TM>/ e.g. C1001 (becomes userId + tmId)
*.xlsx bid data files
""",
)
parser.add_argument(
"--input_root",
default=DEFAULTS["input_root"],
help="Root folder containing segment/order_type/order_side/TM/file.xlsx tree (default: %(default)s)",
)
parser.add_argument(
"--output_root",
default=DEFAULTS["output_root"],
help="Root folder where JSON files are written (same sub-tree) (default: %(default)s)",
)
parser.add_argument(
"--product_code",
default=DEFAULTS["product_code"],
help='Product code string, e.g. "IDAS(01)" (default: %(default)s)',
)
parser.add_argument(
"--password",
default=DEFAULTS["password"],
help="Password applied to every payload (default: %(default)s)",
)
parser.add_argument(
"--ocf_opted",
default=DEFAULTS["ocf_opted"],
help="OCF opted flag Y/N (default: %(default)s)",
)
parser.add_argument(
"--ocf_premium_disc",
type=int,
default=DEFAULTS["ocf_premium_disc"],
help="OCF premium discount integer (default: %(default)s)",
)
parser.add_argument(
"--ocf_qty",
type=int,
default=DEFAULTS["ocf_qty"],
help="OCF quantity integer (default: %(default)s)",
)
args = parser.parse_args()
process_all(vars(args))
if __name__ == "__main__":
main()