blessedpug commited on
Commit
06675a6
·
1 Parent(s): 74f57ab

Medical Form Implemented

Browse files
app.py CHANGED
@@ -1,40 +1,40 @@
1
  import gradio as gr
2
- from pipeline import extract_info, extract_child_fee_info
3
- from pdf2image import convert_from_path
 
 
4
 
5
 
6
 
7
  with gr.Blocks() as demo:
8
  with gr.Tabs():
9
- with gr.Tab("Single Upload"):
10
  with gr.Row():
11
  with gr.Column(scale=2):
12
- img_input = gr.Image(type="pil",label="Image Upload",elem_id="upload-img",show_label=False,height=512,width=512)
 
 
 
 
 
 
13
 
14
  with gr.Column(scale=2):
15
- output_box = gr.Markdown(
16
- value="""```json
17
- {
18
- "merchant": "",
19
- "date": "",
20
- "total_amount": null,
21
- "items": [
22
- {
23
- "description": "",
24
- "amount": null
25
- }
26
- ]
27
- }
28
- ```""",
29
-
30
- label="Extracted Info", elem_id="output-box", show_label=False
31
  )
32
- img_input.upload(fn=extract_info, inputs=img_input, outputs=output_box)
33
 
34
 
35
 
36
-
37
- with gr.Tab("Reimbursement Form"):
38
  with gr.Row():
39
  with gr.Column(scale=2):
40
  img_input = gr.Image(
@@ -48,17 +48,12 @@ with gr.Blocks() as demo:
48
 
49
  with gr.Column(scale=2):
50
  # Dropdown for form names
51
- form_dropdown = gr.Dropdown(
52
- choices=["Child Fee Reimbursement", "Medical Reimbursement", "Other Form"],
53
- label="Select Form",
54
- value="Child Fee Reimbursement",
55
- multiselect=False,
56
- interactive=True,
57
- )
58
 
59
  # 2x2 grid for info fields
60
  with gr.Row():
61
  emp_name = gr.Textbox(label="Employee Name")
 
62
  emp_code = gr.Textbox(label="Employee Code")
63
  with gr.Row():
64
  department = gr.Textbox(label="Department")
@@ -72,11 +67,45 @@ with gr.Blocks() as demo:
72
  outputs=preview_output
73
  )
74
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  # CSS:
76
  gr.HTML("""
77
  <style>
78
  #output-box .prose, #output-box .prose pre, #output-box .prose code {
79
- font-size: 22px !important;
80
  }
81
  </style>
82
  """)
 
1
  import gradio as gr
2
+ from pipeline import extract_info_batch, extract_child_fee_info,extract_medical_info
3
+ from PIL import Image
4
+
5
+
6
 
7
 
8
 
9
  with gr.Blocks() as demo:
10
  with gr.Tabs():
11
+ with gr.Tab("Receipts Upload"):
12
  with gr.Row():
13
  with gr.Column(scale=2):
14
+ batch_img_input = gr.File(
15
+ file_types=["image"],
16
+ label="Batch Image Upload",
17
+ elem_id="batch-upload-img",
18
+ show_label=True,
19
+ file_count="multiple"
20
+ )
21
 
22
  with gr.Column(scale=2):
23
+ batch_output_box = gr.Markdown(
24
+ value="Upload Images to extract information",
25
+ label="Batch Extracted Info",
26
+ elem_id="batch-output-box",
27
+ show_label=True
28
+ )
29
+ batch_img_input.change(
30
+ fn=extract_info_batch,
31
+ inputs=batch_img_input,
32
+ outputs=batch_output_box
 
 
 
 
 
 
33
  )
 
34
 
35
 
36
 
37
+ with gr.Tab("Child Fee Reimbursement Form"):
 
38
  with gr.Row():
39
  with gr.Column(scale=2):
40
  img_input = gr.Image(
 
48
 
49
  with gr.Column(scale=2):
50
  # Dropdown for form names
51
+ gr.Markdown("## Child Fee Reimbursement")
 
 
 
 
 
 
52
 
53
  # 2x2 grid for info fields
54
  with gr.Row():
55
  emp_name = gr.Textbox(label="Employee Name")
56
+
57
  emp_code = gr.Textbox(label="Employee Code")
58
  with gr.Row():
59
  department = gr.Textbox(label="Department")
 
67
  outputs=preview_output
68
  )
69
 
70
+
71
+ with gr.Tab("Medical Reimbursement Form"):
72
+ with gr.Row():
73
+ with gr.Column(scale=2):
74
+ medical_img_input = gr.Image(
75
+ type="pil",
76
+ label="Image Upload",
77
+ elem_id="upload-img",
78
+ show_label=False,
79
+ height=512,
80
+ width=512
81
+ )
82
+ with gr.Column(scale=2):
83
+ with gr.Row():
84
+ med_company_name = gr.Dropdown(choices=["NetSol Technologies Ltd.","NetSol Innovation Private Ltd."], interactive=True, multiselect=False)
85
+ med_emp_name = gr.Textbox(label="Employee Name")
86
+ med_department = gr.Textbox(label="Department")
87
+ with gr.Row():
88
+ med_designation = gr.Textbox(label="Designation")
89
+ med_ext_code = gr.Textbox(label="Extention No.")
90
+ med_emp_code = gr.Textbox(label="Employee Code")
91
+ medical_upload_btn = gr.Button("Upload and Process")
92
+ preview_medical_output = gr.File(label="Download Filled Form")
93
+
94
+
95
+ medical_upload_btn.click(
96
+ fn=extract_medical_info,
97
+ inputs=[medical_img_input,med_emp_name,med_emp_code,med_department,med_designation,med_company_name,med_ext_code],
98
+ outputs=preview_medical_output
99
+ )
100
+
101
+
102
+
103
+
104
  # CSS:
105
  gr.HTML("""
106
  <style>
107
  #output-box .prose, #output-box .prose pre, #output-box .prose code {
108
+ font-size: 30px !important;
109
  }
110
  </style>
111
  """)
form_fill.py CHANGED
@@ -40,3 +40,54 @@ def fill_child_fee_pdf(
40
  annotation.AP = None # Remove old appearance so new value appears
41
  PdfWriter().write(output_pdf_path, template_pdf)
42
  return output_pdf_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  annotation.AP = None # Remove old appearance so new value appears
41
  PdfWriter().write(output_pdf_path, template_pdf)
42
  return output_pdf_path
43
+
44
+
45
+ def fill_medical_pdf(
46
+ template_pdf_path,
47
+ output_pdf_path,
48
+ company,
49
+ extension_no,
50
+ employee_name,
51
+ employee_code,
52
+ department,
53
+ date,
54
+ total,
55
+ designation,
56
+ billing_month,
57
+ claims # List of dicts: [{'name': ..., 'relationship': ..., 'category': ..., 'detail': ..., 'amount': ...}]
58
+ ):
59
+ data_dict = {
60
+ 'company': company,
61
+ 'extension_no': extension_no,
62
+ 'employee_name': employee_name,
63
+ 'employee_code': employee_code,
64
+ 'department': department,
65
+ 'designation': designation,
66
+ 'date': date,
67
+ 'billing_month': billing_month,
68
+ 'total': str(total),
69
+ 'current_date': datetime.now().strftime("%d-%b-%Y"),
70
+ }
71
+
72
+ # Map each row of claims to field names
73
+ for idx, claim in enumerate(claims, start=1):
74
+ data_dict[f'name_{idx}'] = claim.get('name', '')
75
+ data_dict[f'relationship_{idx}'] = claim.get('relationship', '')
76
+ data_dict[f'category_{idx}'] = claim.get('category', '')
77
+ data_dict[f'detail_{idx}'] = claim.get('detail', '')
78
+ data_dict[f'amount_{idx}'] = str(claim.get('amount', ''))
79
+
80
+ # Fill the PDF
81
+ template_pdf = PdfReader(template_pdf_path)
82
+ for page in template_pdf.pages:
83
+ if not hasattr(page, 'Annots') or not page.Annots:
84
+ continue
85
+ for annotation in page.Annots:
86
+ if annotation.T:
87
+ key = annotation.T[1:-1] # Remove parentheses
88
+ if key in data_dict:
89
+ annotation.V = str(data_dict[key])
90
+ annotation.AP = None # Remove old appearance so new value appears
91
+ PdfWriter().write(output_pdf_path, template_pdf)
92
+ return output_pdf_path
93
+
models.py CHANGED
@@ -27,3 +27,25 @@ class FeeItem(BaseModel):
27
  class ChildFeeForm(BaseModel):
28
  items: List[FeeItem]
29
  total: float # Calculated after parsing
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  class ChildFeeForm(BaseModel):
28
  items: List[FeeItem]
29
  total: float # Calculated after parsing
30
+
31
+
32
+
33
+
34
+ class MedicalClaimItem(BaseModel):
35
+ name: str # Patient name
36
+ relationship: str # self, spouse, parent, child
37
+ category: str # in-patient, out-patient, maternity(cesarean), maternity(normal)
38
+ detail: str # doctor's fee, diagnostic tests, medicines, other hospitalization
39
+ amount: float
40
+
41
+ class MedicalReimbursementForm(BaseModel):
42
+ company: Optional[str] = None
43
+ extension_no: Optional[str] = None
44
+ employee_name: str
45
+ employee_code: str
46
+ department: Optional[str] = None
47
+ designation: Optional[str] = None
48
+ date: Optional[str] = None
49
+ billing_month: Optional[str] = None
50
+ claims: List[MedicalClaimItem]
51
+ total: float
outputs/filled_child_fee_form_e3fba6d8482a476dade270c022cc64e2.pdf DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:fa5b02270d310e55abfdf36281e54e88928ad3b71d19f034b784b1616a2c9eb5
3
- size 115542
 
 
 
 
pipeline.py CHANGED
@@ -5,9 +5,11 @@ import os, uuid
5
  from PIL import Image
6
  import base64
7
  import json
8
- from models import ReceiptData, ChildFeeForm
9
- from form_fill import fill_child_fee_pdf
10
  from fraud import process_receipt
 
 
11
 
12
  load_dotenv()
13
  openai.api_key = os.getenv("OPENAI_API_KEY", "").strip()
@@ -37,6 +39,7 @@ reciept_system_prompt = (
37
  "- Do not add any explanation or extra text—only the JSON."
38
  )
39
 
 
40
  fee_bill_system_prompt = (
41
  "You are an expert at extracting data from fee bills. "
42
  "Read the provided image of a child fee bill and return a JSON object that matches the following Pydantic model:\n"
@@ -58,6 +61,29 @@ fee_bill_system_prompt = (
58
  )
59
 
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
 
63
  def pil_to_bytes(pil_img, quality=70):
@@ -170,3 +196,79 @@ def extract_child_fee_info(img_input, emp_name, emp_code, department):
170
  except Exception as e:
171
  print("ERROR:", e)
172
  return None # or f"Error: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  from PIL import Image
6
  import base64
7
  import json
8
+ from models import ReceiptData, ChildFeeForm, MedicalReimbursementForm
9
+ from form_fill import fill_child_fee_pdf, fill_medical_pdf
10
  from fraud import process_receipt
11
+ from datetime import datetime
12
+
13
 
14
  load_dotenv()
15
  openai.api_key = os.getenv("OPENAI_API_KEY", "").strip()
 
39
  "- Do not add any explanation or extra text—only the JSON."
40
  )
41
 
42
+
43
  fee_bill_system_prompt = (
44
  "You are an expert at extracting data from fee bills. "
45
  "Read the provided image of a child fee bill and return a JSON object that matches the following Pydantic model:\n"
 
61
  )
62
 
63
 
64
+ medical_form_system_prompt = (
65
+ "You are an expert at extracting structured data from tabular forms containing sample data. "
66
+ "Your task is to read the provided form and return a JSON object that matches the following Pydantic model:\n"
67
+ "class Item(BaseModel):\n"
68
+ " name: str #the patient name\n"
69
+ " relationship: # self, spouse, parent, child\n"
70
+ " category: # in-patient, out-patient, maternity(cesarean), maternity(normal)\n"
71
+ " detail: # doctor's fee, diagnostic tests, medicines, other hospitalization\n"
72
+ " bill_month: Optional[str] = None # Bill Month Field, if not directly stated, find the date and infer the month from that, if not found return null\n"
73
+ " amount: float\n"
74
+ "class Form(BaseModel):\n"
75
+ " claims: List[Item]\n"
76
+ " total: float\n"
77
+ "- Extract only the above information. If a value is missing, set it to null, \"\", or an empty list as appropriate.\n"
78
+ "- For the claims field, provide a list of objects with name, relationship, category, detail, and amount.\n"
79
+ "- The total field must be the sum of all amount values in claims.\n"
80
+ "- Only return a valid JSON object matching the model above.\n"
81
+ "- Do not add any explanation or extra text—only the JSON."
82
+ "- Try your very best to extract this information as it is very important that you do so\n"
83
+ "- If you are unable to extract information, return an empty json in the format requested above, never give a response other than a json"
84
+ )
85
+
86
+
87
 
88
 
89
  def pil_to_bytes(pil_img, quality=70):
 
196
  except Exception as e:
197
  print("ERROR:", e)
198
  return None # or f"Error: {str(e)}"
199
+
200
+
201
+
202
+ def extract_info_batch(file_list):
203
+ """
204
+ Accepts a list of file objects/paths, processes each as a PIL image, and returns results.
205
+ """
206
+ results = []
207
+ for file in file_list:
208
+ img = Image.open(file)
209
+ results.append(extract_info(img))
210
+ return "\n\n".join(results)
211
+
212
+
213
+
214
+ def extract_medical_info(pil_img, emp_name, emp_code, department, designation, company, extension_no,):
215
+ processed_image = preprocess_image(pil_img)
216
+ img_bytes = pil_to_bytes(processed_image)
217
+ img_base64 = base64.b64encode(img_bytes.getvalue()).decode("utf-8")
218
+ response = openai.chat.completions.create(
219
+ model="gpt-4o",
220
+ messages=[
221
+ {"role": "system", "content": medical_form_system_prompt},
222
+ {"role": "user",
223
+ "content": [
224
+ {"type": "text", "text": "Here is a child fee bill image:"},
225
+ {"type": "image_url", "image_url": {"url": "data:image/png;base64," + img_base64}}
226
+ ]}
227
+ ]
228
+ )
229
+ raw_output = response.choices[0].message.content
230
+ print(raw_output)
231
+ try:
232
+ if raw_output.startswith("```"):
233
+ raw_output = raw_output.strip("` \n")
234
+ if raw_output.startswith("json"):
235
+ raw_output = raw_output[4:].strip()
236
+ data = json.loads(raw_output)
237
+ print(data)
238
+ # Validate if needed:
239
+ # ChildFeeForm(**data)
240
+
241
+ claims = data.get("claims", [])
242
+ bill_month = ""
243
+ if claims and "bill_month" in claims[0]:
244
+ bill_month = claims[0]["bill_month"]
245
+
246
+ date = datetime.now().strftime("%d-%b-%Y") # e.g., "10-Jun-2024"
247
+ total = data.get("total", 0)
248
+
249
+ print("bill month:",bill_month)
250
+
251
+ print("total:",total)
252
+ os.makedirs("outputs", exist_ok=True)
253
+ output_pdf_path = f"outputs/filled_medical_form_{uuid.uuid4().hex}.pdf"
254
+
255
+
256
+ filled_pdf_path = fill_medical_pdf(
257
+ template_pdf_path="Medical Reim. Form.pdf",
258
+ output_pdf_path=output_pdf_path,
259
+ company=company,
260
+ employee_name=emp_name,
261
+ employee_code=emp_code,
262
+ department=department,
263
+ designation=designation,
264
+ extension_no=extension_no,
265
+ billing_month=bill_month,
266
+ claims=claims,
267
+ date= date,
268
+ total=total
269
+ )
270
+
271
+ return filled_pdf_path # Return path to Gradio for download
272
+ except Exception as e:
273
+ print("ERROR:", e)
274
+ return None # or f"Error: {str(e)}"
CHILD FEE REIMBURSEMENT FORM.pdf → templates/CHILD FEE REIMBURSEMENT FORM.pdf RENAMED
File without changes
outputs/filled_child_fee_form_6dfe1052f5be4bbc8a78711a456a3cc9.pdf → templates/Medical Reim. Form.pdf RENAMED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:48066dd238b5a6eda1e8cd8647afc31074c61b7b95946e6b4329426f4a818331
3
- size 115543
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c42ef819cd41595124559fb1d5ae4bd290eb5152d477cc0e61ec89f7d13f2380
3
+ size 103497
templates/medical_form.html ADDED
@@ -0,0 +1,286 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Medical Reimbursement Form (Applicable for Outpatient)</title>
6
+ <style>
7
+ body {
8
+ font-family: 'Times New Roman', Times, serif;
9
+ background: #fff;
10
+ margin: 0;
11
+ padding: 40px 0;
12
+ }
13
+ .form-container {
14
+ width: 900px;
15
+ margin: 0 auto;
16
+ border: 2px solid #000;
17
+ background: #fff;
18
+ }
19
+ .form-header {
20
+ display: flex;
21
+ align-items: flex-start;
22
+ padding: 15px 30px 0 20px;
23
+ }
24
+ .logo-placeholder {
25
+ width: 90px;
26
+ height: 90px;
27
+ background: #f2f2f2;
28
+ border: 1px solid #ddd;
29
+ margin-right: 18px;
30
+ }
31
+ .header-title {
32
+ flex: 1;
33
+ text-align: center;
34
+ }
35
+ .header-title h2 {
36
+ font-size: 24px;
37
+ margin: 0;
38
+ font-weight: bold;
39
+ }
40
+ .header-title h3 {
41
+ font-size: 18px;
42
+ margin: 0;
43
+ font-weight: normal;
44
+ }
45
+ .form-details {
46
+ display: flex;
47
+ flex-wrap: wrap;
48
+ padding: 10px 30px 0 30px;
49
+ font-size: 17px;
50
+ }
51
+ .form-details-col {
52
+ flex: 1 1 50%;
53
+ }
54
+ .form-details-row {
55
+ display: flex;
56
+ align-items: center;
57
+ margin-bottom: 7px;
58
+ }
59
+ .form-details-label {
60
+ width: 140px;
61
+ display: inline-block;
62
+ }
63
+ .form-details-input {
64
+ border: none;
65
+ border-bottom: 1.2px solid #000;
66
+ width: 250px;
67
+ height: 22px;
68
+ font-size: 16px;
69
+ background: none;
70
+ margin-left: 4px;
71
+ margin-right: 4px;
72
+ }
73
+ .form-details-input:focus {
74
+ outline: none;
75
+ background: #eef;
76
+ }
77
+ .form-table-container {
78
+ margin: 25px 20px 0 20px;
79
+ }
80
+ table {
81
+ width: 100%;
82
+ border-collapse: collapse;
83
+ margin-bottom: 0;
84
+ }
85
+ th, td {
86
+ border: 1px solid #000;
87
+ padding: 7px 4px;
88
+ font-size: 16px;
89
+ text-align: center;
90
+ }
91
+ th {
92
+ background: #ddd;
93
+ font-weight: bold;
94
+ }
95
+ .table-title-row th {
96
+ border-bottom: 2px solid #000;
97
+ }
98
+ .table-claim-col {
99
+ width: 120px;
100
+ }
101
+ .table-input {
102
+ width: 95%;
103
+ font-size: 15px;
104
+ border: none;
105
+ border-bottom: 1px solid #555;
106
+ background: none;
107
+ text-align: center;
108
+ }
109
+ .table-input:focus {
110
+ outline: none;
111
+ background: #eef;
112
+ }
113
+ .total-row td {
114
+ border: none;
115
+ text-align: right;
116
+ font-weight: bold;
117
+ font-size: 17px;
118
+ padding-right: 24px;
119
+ }
120
+ .signature-row {
121
+ height: 60px;
122
+ }
123
+ .signature-cell {
124
+ text-align: right;
125
+ padding-right: 90px;
126
+ vertical-align: bottom;
127
+ }
128
+ .notes-section {
129
+ font-size: 14px;
130
+ margin: 8px 22px 10px 24px;
131
+ }
132
+ .notes-section ol,
133
+ .notes-section ul {
134
+ margin-top: 0;
135
+ margin-bottom: 0;
136
+ }
137
+ .notes-section li {
138
+ margin-bottom: 4px;
139
+ }
140
+ .bottom-line {
141
+ border-bottom: 1.5px solid #000;
142
+ margin-top: 30px;
143
+ width: 250px;
144
+ }
145
+ @media (max-width: 950px) {
146
+ .form-container {
147
+ width: 98vw;
148
+ }
149
+ }
150
+ @media (max-width: 650px) {
151
+ .form-header, .form-details, .form-table-container {
152
+ padding-left: 5px !important;
153
+ padding-right: 5px !important;
154
+ }
155
+ .form-container {
156
+ padding: 0 1vw;
157
+ }
158
+ }
159
+ </style>
160
+ </head>
161
+ <body>
162
+ <div class="form-container">
163
+ <div class="form-header">
164
+ <div class="logo-placeholder">
165
+ <!-- Logo goes here -->
166
+ </div>
167
+ <div class="header-title">
168
+ <h2>Medical Reimbursement Form</h2>
169
+ <h3>(Applicable for Outpatient )</h3>
170
+ </div>
171
+ </div>
172
+ <form>
173
+ <div class="form-details">
174
+ <div class="form-details-col">
175
+ <div class="form-details-row">
176
+ <span class="form-details-label">Company:</span>
177
+ <input class="form-details-input" type="text" name="company">
178
+ </div>
179
+ <div class="form-details-row">
180
+ <span class="form-details-label">Name:</span>
181
+ <input class="form-details-input" type="text" name="name">
182
+ </div>
183
+ <div class="form-details-row">
184
+ <span class="form-details-label">Department:</span>
185
+ <input class="form-details-input" type="text" name="department">
186
+ </div>
187
+ <div class="form-details-row">
188
+ <span class="form-details-label">Designation:</span>
189
+ <input class="form-details-input" type="text" name="designation">
190
+ </div>
191
+ </div>
192
+ <div class="form-details-col">
193
+ <div class="form-details-row">
194
+ <span class="form-details-label">Extension No:</span>
195
+ <input class="form-details-input" type="text" name="extension">
196
+ </div>
197
+ <div class="form-details-row">
198
+ <span class="form-details-label">Employee Code:</span>
199
+ <input class="form-details-input" type="text" name="employee_code">
200
+ </div>
201
+ <div class="form-details-row">
202
+ <span class="form-details-label">Date:</span>
203
+ <input class="form-details-input" type="date" name="date" style="width:180px;">
204
+ </div>
205
+ <div class="form-details-row">
206
+ <span class="form-details-label">Billing Month:</span>
207
+ <input class="form-details-input" type="text" name="billing_month" placeholder="mm/yy" style="width:90px;">
208
+ <span style="margin-left:10px;">(mm/yy)</span>
209
+ </div>
210
+ </div>
211
+ </div>
212
+ <div class="form-table-container">
213
+ <table>
214
+ <tr class="table-title-row">
215
+ <th>Name</th>
216
+ <th>Relationship</th>
217
+ <th>Category</th>
218
+ <th class="table-claim-col">Detail</th>
219
+ <th class="table-claim-col">Amount</th>
220
+ </tr>
221
+ <tbody>
222
+ {{claims_rows}}
223
+ </tbody>
224
+ </table>
225
+ <table style="margin-top: 0;">
226
+ <tr class="total-row">
227
+ <td colspan="4" style="border: none;"></td>
228
+ <td style="border-top: none; border-left: 1px solid #000;">Total -
229
+ <input style="width: 80px; border: none; border-bottom: 1px solid #000; font-size: 16px; background: none; text-align: center;" type="number" step="0.01" min="0" name="total" readonly id="total_amount">
230
+ </td>
231
+ </tr>
232
+ <tr class="signature-row">
233
+ <td colspan="5" class="signature-cell">
234
+ <div style="margin-top:20px;">
235
+ ________________________________<br>
236
+ Employee's Signature
237
+ </div>
238
+ </td>
239
+ </tr>
240
+ </table>
241
+ </div>
242
+ </form>
243
+ <div class="notes-section">
244
+ <ol>
245
+ <li>No claim will be processed in case:
246
+ <ul style="list-style-type: lower-alpha; margin-left: 20px;">
247
+ <li>Supporting documents are not attached.</li>
248
+ <li>Form is incomplete.</li>
249
+ <li>Claim is time barred <span style="text-decoration:underline;">i.e.</span> not submitted within thirty (30) days after the expense is incurred.</li>
250
+ <li>Any violation of applicable policy and procedure.</li>
251
+ </ul>
252
+ </li>
253
+ <li>
254
+ <span style="text-decoration:underline;">"Category"</span> refers to type of the claim <span style="text-decoration:underline;">i.e.</span> in-patient, out-patient, maternity (cesarean), maternity (normal).
255
+ </li>
256
+ <li>
257
+ <span style="text-decoration:underline;">"Detail"</span> refers to type of the expenditure <span style="text-decoration:underline;">i.e.</span> doctor's fee, diagnostic tests, medicines, other hospitalization charges.
258
+ </li>
259
+ <li>
260
+ Expenses incurred during probation are considered to be time barred if not claimed within thirty days after confirmation.
261
+ </li>
262
+ </ol>
263
+ </div>
264
+ </div>
265
+ <script>
266
+ // Auto sum the Amount columns
267
+ const amountFields = [
268
+ document.querySelector('input[name="claim_amount1"]'),
269
+ document.querySelector('input[name="claim_amount2"]'),
270
+ document.querySelector('input[name="claim_amount3"]'),
271
+ document.querySelector('input[name="claim_amount4"]')
272
+ ];
273
+ const totalField = document.getElementById('total_amount');
274
+ amountFields.forEach(f => {
275
+ f.addEventListener('input', () => {
276
+ let total = 0;
277
+ amountFields.forEach(ff => {
278
+ let val = parseFloat(ff.value);
279
+ if (!isNaN(val)) total += val;
280
+ });
281
+ totalField.value = total > 0 ? total.toFixed(2) : '';
282
+ });
283
+ });
284
+ </script>
285
+ </body>
286
+ </html>