Ninad077 commited on
Commit
f76a438
·
verified ·
1 Parent(s): 4da9968

Upload 17 files

Browse files
Fynd_logo_hd.jpeg ADDED
alerter_logo.jpg ADDED
alerter_logo2.jpg ADDED
app.py ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import smtplib
4
+ from email.mime.text import MIMEText
5
+ from email.mime.multipart import MIMEMultipart
6
+ import gspread
7
+ from oauth2client.service_account import ServiceAccountCredentials
8
+ from streamlit_option_menu import option_menu
9
+ from io import BytesIO
10
+ import requests
11
+ from email.mime.application import MIMEApplication
12
+ import os
13
+ from email.mime.base import MIMEBase
14
+ from email import encoders
15
+ import base64
16
+ from utils import read_file, get_content_type, get_base64_image, send_message_via_email, send_message_via_webhook, EMAIL_HOST, EMAIL_PORT, EMAIL_HOST_USER, EMAIL_HOST_PASSWORD, send_file_to_slack, send_file_to_slack_up
17
+ from html_templates import logo, slack_message_title, upload_doc_title, channel_member_title, Slack_title, email_body, email_subject, button_styles, tooltip_message_slack, email_title
18
+ from slack import Slack_email_addresses, gmail_addresses, Webhook_urls
19
+
20
+
21
+ st.set_page_config(page_title="Alerter",page_icon="",layout="centered")
22
+
23
+
24
+ # Display logo using st.logo
25
+ st.markdown(logo, unsafe_allow_html=True)
26
+ st.logo("alerter_logo.jpg")
27
+
28
+
29
+ st.markdown(Slack_title, unsafe_allow_html=True)
30
+ st.write("")
31
+ st.markdown(tooltip_message_slack, unsafe_allow_html = True)
32
+ st.write("")
33
+
34
+
35
+ def main():
36
+
37
+ menu_options = [
38
+ {"label": "Slack a text", "icon": "📄", "description": "Slack channel members"},
39
+ {"label": "Slack a doc", "icon": "📄", "description": "Slack channel members"},
40
+ {"label": "Gmail a member", "icon": "📊", "description": "Email channel members"},
41
+ {"label": "Gmail anyone", "icon": "📊", "description": "Email anyone"},
42
+ ]
43
+
44
+ # Create the custom option menu
45
+ selected_option = option_menu(
46
+ menu_title="Select Integration", # Title of the menu
47
+ options=[option["label"] for option in menu_options], # Displayed options
48
+ icons=[option["icon"] for option in menu_options], # Icons next to options
49
+ menu_icon="cast", # Icon for the entire menu
50
+ default_index=0, # Default selected option
51
+ orientation="horizontal" # Orientation of the menu (can be vertical or horizontal)
52
+ )
53
+
54
+
55
+ if selected_option == "Slack a text":
56
+ # Dropdown for channels/members
57
+ options = list(Webhook_urls.keys())
58
+ st.markdown(channel_member_title, unsafe_allow_html=True)
59
+ selection = st.multiselect("", options, help = 'Select the channels or members you want to Slack a message')
60
+
61
+ #Slack message title
62
+ st.markdown(slack_message_title, unsafe_allow_html=True)
63
+ message = st.text_area("", "", help = 'Enter the Slack message')
64
+
65
+ #Slack button
66
+ st.markdown(button_styles, unsafe_allow_html = True)
67
+ if st.button("Send to Slack"):
68
+ if not message:
69
+ st.error("Please enter a message before sending.")
70
+ elif not selection:
71
+ st.error("Please select at least one channel or member.")
72
+ else:
73
+ # Loop through the selected channels or members
74
+ for recipient in selection:
75
+ webhook_url = Webhook_urls.get(recipient)
76
+ if webhook_url:
77
+ success, response_message = send_message_via_webhook(message, webhook_url)
78
+ if success:
79
+ st.success(f"Message sent to {recipient} successfully!")
80
+ else:
81
+ st.error(f"Failed to send message to {recipient}. Error: {response_message}")
82
+ else:
83
+ st.error(f"Webhook URL for {recipient} is not configured.")
84
+
85
+
86
+ elif selected_option == "Slack a doc":
87
+ # Dropdown for channels/members
88
+ options = list(Slack_email_addresses.keys())
89
+ st.markdown(channel_member_title, unsafe_allow_html=True)
90
+ selection = st.multiselect("", options, help = 'Select the channels or members you want to Slack a message')
91
+
92
+ #File uploader
93
+ st.markdown(upload_doc_title, unsafe_allow_html=True)
94
+ uploaded_file = st.file_uploader("", type=["pdf", "docx", "png", "jpeg", "xlsx", "csv", "json"], key="file_uploader", help = 'Upload the files you need to email', accept_multiple_files= True)
95
+
96
+ #Slack button
97
+ st.markdown(button_styles, unsafe_allow_html = True)
98
+ if st.button("Send to Slack"):
99
+ # Check if a message or file has been provided
100
+ message = None
101
+ if uploaded_file: # Handle file uploads
102
+ files_to_send = []
103
+ for file in uploaded_file:
104
+ files_to_send.append((file.name, file)) # Save file name and object
105
+ else:
106
+ st.error("Please upload at least one document before sending.")
107
+ return
108
+
109
+ if not selection:
110
+ st.error("Please select at least one channel or member.")
111
+ return
112
+
113
+ # Iterate over the selection and send files
114
+ for item in selection:
115
+ webhook_url = Webhook_urls.get(item)
116
+ if webhook_url:
117
+ for filename, file in files_to_send:
118
+ # Send the file as binary
119
+ try:
120
+ response = send_file_to_slack_up(file, webhook_url)
121
+ if response.status_code == 200:
122
+ st.success(f"File '{filename}' sent to {item} via Slack webhook.")
123
+ else:
124
+ st.error(f"Failed to send file '{filename}' to {item}: {response.text}")
125
+ except Exception as e:
126
+ st.error(f"Error sending file '{filename}' to {item}: {str(e)}")
127
+ else:
128
+ st.error(f"No webhook URL found for {item}.")
129
+
130
+ elif selected_option == "Gmail a member":
131
+ # Dropdown for channels/members
132
+ options = list(Slack_email_addresses.keys())
133
+ st.markdown(channel_member_title, unsafe_allow_html=True)
134
+ selection = st.multiselect("", options, help = 'Select the channels or members you want to Email a message')
135
+
136
+ #File uploader
137
+ st.markdown(upload_doc_title, unsafe_allow_html=True)
138
+ uploaded_file = st.file_uploader("", type=["pdf", "docx", "png", "jpeg", "xlsx", "csv", "json"], key="file_uploader", help = 'Upload the files you need to email', accept_multiple_files= True)
139
+
140
+
141
+ st.markdown(email_subject, unsafe_allow_html=True)
142
+ subject = st.text_input("", "",key ="subject_text_input", help = 'Enter the subject of your email')
143
+
144
+ st.markdown(email_body, unsafe_allow_html=True)
145
+ body = st.text_area("", "", key="body_text_area", help = 'Enter the body of of your email')
146
+
147
+ st.markdown(button_styles, unsafe_allow_html=True)
148
+
149
+
150
+ if st.button("Send to Gmail"):
151
+
152
+ message = body
153
+ if not body and not uploaded_file:
154
+ st.error("Please enter a message or upload a document before sending.")
155
+ return
156
+
157
+ if not selection:
158
+ st.error("Please select at least one channel or member")
159
+ return
160
+
161
+ for item in selection:
162
+ email_address = gmail_addresses.get(item)
163
+ if email_address:
164
+ success, response_message = send_message_via_email(message, email_address, uploaded_file, subject, body)
165
+ if success:
166
+ st.success(f"Message sent to {item} via Gmail.")
167
+ else:
168
+ st.error(f"Failed to send message to {item}: {response_message}")
169
+ else:
170
+ st.error(f"No Gmail address found for {item}.")
171
+
172
+
173
+ elif selected_option == "Gmail anyone":
174
+
175
+ st.markdown(email_title, unsafe_allow_html = True)
176
+ st.write("")
177
+ st.write("")
178
+ selection = st.text_area(
179
+ "",
180
+ "",
181
+ key="email_text_input",
182
+ help = 'In case of multiple email addresses, please write them comma-separated. E.g. abc@gmail.com, def@gmail.com'
183
+ )
184
+
185
+ #File uploader
186
+ st.markdown(upload_doc_title, unsafe_allow_html=True)
187
+ uploaded_file = st.file_uploader("", type=["pdf", "docx", "png", "jpeg", "xlsx", "csv", "json"], key="file_uploader", help = 'Upload the files you need to email', accept_multiple_files= True)
188
+
189
+
190
+ st.markdown(email_subject, unsafe_allow_html=True)
191
+ subject = st.text_input("", "",key ="subject_text_input", help = 'Enter the subject of your email')
192
+
193
+
194
+ st.markdown(email_body, unsafe_allow_html=True)
195
+ body = st.text_area("", "", key="body_text_area", help = 'Enter the body of your email')
196
+
197
+
198
+ st.markdown(button_styles, unsafe_allow_html=True)
199
+
200
+
201
+ if st.button("Send to Gmail"):
202
+
203
+ # Validate input
204
+ if not body and not uploaded_file:
205
+ st.error("Please enter a message or upload a document before sending.")
206
+ return
207
+
208
+ if not selection:
209
+ st.error("Please enter at least one email address.")
210
+ return
211
+
212
+
213
+ message = body
214
+
215
+ # Process email addresses
216
+ email_addresses = [email.strip() for email in selection.split(",") if email.strip()]
217
+
218
+ if not email_addresses:
219
+ st.error("Please provide valid email addresses.")
220
+ return
221
+
222
+ # Send email
223
+ for email_address in email_addresses:
224
+ success, response_message = send_message_via_email(message, email_address, uploaded_file, subject, body)
225
+ if success:
226
+ st.success(f"Message sent to {email_address} via Gmail.")
227
+ else:
228
+ st.error(f"Failed to send message to {email_address}: {response_message}")
229
+
230
+ if __name__ == "__main__":
231
+ main()
232
+
233
+
html_templates.py ADDED
@@ -0,0 +1,928 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ logo = """
2
+ <style>
3
+ div[data-testid="stSidebarHeader"] > img, div[data-testid="collapsedControl"] > img {
4
+ height: 4rem; /* Increased height */
5
+ width: 13rem; /* Adjust width proportionally */
6
+ }
7
+
8
+ div[data-testid="stSidebarHeader"], div[data-testid="stSidebarHeader"] > *,
9
+ div[data-testid="collapsedControl"], div[data-testid="collapsedControl"] > * {
10
+ display: flex;
11
+ align-items: center;
12
+ }
13
+ </style>
14
+ """
15
+
16
+ BigQuery_upload_title = """
17
+ <style>
18
+ .fixed-title {
19
+ font-size: 40px;
20
+ color: #ffffff;
21
+ background-image: linear-gradient(to right, #ff0000, #ffdab9);
22
+ background-clip: text;
23
+ -webkit-background-clip: text;
24
+ text-fill-color: transparent;
25
+ -webkit-text-fill-color: transparent;
26
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.4);
27
+ }
28
+ </style>
29
+ <h1 class="fixed-title">BigQuery upload</h1>
30
+ """
31
+
32
+ fynder_title = """
33
+ <style>
34
+ .fixed-title {
35
+ font-size: 50px;
36
+ color: #ffffff;
37
+ background-image: linear-gradient(to right, #ff0000, #ffdab9);
38
+ background-clip: text;
39
+ -webkit-background-clip: text;
40
+ text-fill-color: transparent;
41
+ -webkit-text-fill-color: transparent;
42
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.4);
43
+ }
44
+ </style>
45
+ <h1 class="fixed-title">Fynder</h1>
46
+ """
47
+
48
+ Appended_data_title = """
49
+ <style>
50
+ .fixed-title {
51
+ font-size: 40px;
52
+ color: #ffffff;
53
+ background-image: linear-gradient(to right, #ff0000, #ffdab9);
54
+ background-clip: text;
55
+ -webkit-background-clip: text;
56
+ text-fill-color: transparent;
57
+ -webkit-text-fill-color: transparent;
58
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.4);
59
+ }
60
+ </style>
61
+ <h1 class="fixed-title">Appended data</h1>
62
+ """
63
+
64
+
65
+ Merger_title = """
66
+ <style>
67
+ .fixed-title {
68
+ font-size: 40px;
69
+ color: #ffffff;
70
+ background-image: linear-gradient(to right, #ff0000, #ffdab9);
71
+ background-clip: text;
72
+ -webkit-background-clip: text;
73
+ text-fill-color: transparent;
74
+ -webkit-text-fill-color: transparent;
75
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.4);
76
+ }
77
+ </style>
78
+ <h1 class="fixed-title">Merger</h1>
79
+ """
80
+
81
+
82
+ TDS_title = """
83
+ <style>
84
+ .fixed-title {
85
+ font-size: 40px;
86
+ color: #ffffff;
87
+ background-image: linear-gradient(to right, #ff0000, #ffdab9);
88
+ background-clip: text;
89
+ -webkit-background-clip: text;
90
+ text-fill-color: transparent;
91
+ -webkit-text-fill-color: transparent;
92
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.4);
93
+ }
94
+ </style>
95
+ <h1 class="fixed-title">TDS validation</h1>
96
+ """
97
+
98
+
99
+ table_id_placeholder = """
100
+ <html>
101
+ <head>
102
+ <style>
103
+ .button {
104
+ display: inline-block;
105
+ padding: 10px 20px;
106
+ border-radius: 12px;
107
+ background: linear-gradient(to bottom, #f8f9fa, #e0e0e0);
108
+ box-shadow:
109
+ 0 6px 12px rgba(0, 0, 0, 0.3),
110
+ 0 8px 16px rgba(0, 0, 0, 0.2),
111
+ inset 0 -2px 4px rgba(255, 255, 255, 0.6);
112
+ text-align: center;
113
+ position: relative;
114
+ transform: translateY(4px);
115
+ transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
116
+ cursor: pointer;
117
+ user-select: none;
118
+ }
119
+ .button:hover {
120
+ box-shadow:
121
+ 0 8px 16px rgba(0, 0, 0, 0.3),
122
+ 0 12px 24px rgba(0, 0, 0, 0.2);
123
+ transform: translateY(2px);
124
+ }
125
+ .button:active {
126
+ box-shadow:
127
+ 0 4px 8px rgba(0, 0, 0, 0.3),
128
+ 0 6px 12px rgba(0, 0, 0, 0.2);
129
+ transform: translateY(0);
130
+ }
131
+ </style>
132
+ </head>
133
+ <body>
134
+ <div class="button">
135
+ <h3 style="
136
+ font-size: 20px;
137
+ color: #ffffff;
138
+ background-image: linear-gradient(to right, #800000, #ff0000, #ffdab9);
139
+ background-clip: text;
140
+ -webkit-background-clip: text;
141
+ text-fill-color: transparent;
142
+ -webkit-text-fill-color: transparent;
143
+ margin: 0;
144
+ text-shadow: 0 2px 5px rgba(0, 0, 0, 0.4);
145
+ ">Enter table id</h3>
146
+ </div>
147
+ </body>
148
+ </html>
149
+ """
150
+
151
+ uploader = """
152
+ <html>
153
+ <head>
154
+ <style>
155
+ .button {
156
+ display: inline-block;
157
+ padding: 10px 20px;
158
+ border-radius: 12px;
159
+ background: linear-gradient(to bottom, #f8f9fa, #e0e0e0);
160
+ box-shadow:
161
+ 0 6px 12px rgba(0, 0, 0, 0.3),
162
+ 0 8px 16px rgba(0, 0, 0, 0.2),
163
+ inset 0 -2px 4px rgba(255, 255, 255, 0.6);
164
+ text-align: center;
165
+ position: relative;
166
+ transform: translateY(4px);
167
+ transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
168
+ cursor: pointer;
169
+ user-select: none;
170
+ }
171
+ .button:hover {
172
+ box-shadow:
173
+ 0 8px 16px rgba(0, 0, 0, 0.3),
174
+ 0 12px 24px rgba(0, 0, 0, 0.2);
175
+ transform: translateY(2px);
176
+ }
177
+ .button:active {
178
+ box-shadow:
179
+ 0 4px 8px rgba(0, 0, 0, 0.3),
180
+ 0 6px 12px rgba(0, 0, 0, 0.2);
181
+ transform: translateY(0);
182
+ }
183
+ </style>
184
+ </head>
185
+ <body>
186
+ <div class="button">
187
+ <h3 style="
188
+ font-size: 20px;
189
+ color: #ffffff;
190
+ background-image: linear-gradient(to right, #800000, #ff0000, #ffdab9);
191
+ background-clip: text;
192
+ -webkit-background-clip: text;
193
+ text-fill-color: transparent;
194
+ -webkit-text-fill-color: transparent;
195
+ margin: 0;
196
+ text-shadow: 0 2px 5px rgba(0, 0, 0, 0.4);
197
+ ">Upload the CSV file</h3>
198
+ </div>
199
+ </body>
200
+ </html>
201
+ """
202
+
203
+ button_styles = """
204
+ <style>
205
+ div.stButton > button {
206
+ color: #ffffff; /* Text color */
207
+ font-size: 30px;
208
+ background-image: linear-gradient(to right, #800000, #ff0000); /* Maroon to light red gradient */
209
+ border: none;
210
+ padding: 10px 20px;
211
+ cursor: pointer;
212
+ border-radius: 15px;
213
+ display: inline-block;
214
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 8px 15px rgba(0, 0, 0, 0.1); /* Box shadow */
215
+ transition: all 0.3s ease; /* Smooth transition on hover */
216
+ }
217
+ div.stButton > button:hover {
218
+ background-color: #00ff00; /* Hover background color */
219
+ color: #ff0000; /* Hover text color */
220
+ box-shadow: 0 6px 10px rgba(0, 0, 0, 0.2), 0 12px 20px rgba(0, 0, 0, 0.2); /* Box shadow on hover */
221
+ }
222
+ </style>
223
+ """
224
+ button_styles_fynder = """
225
+ <style>
226
+ div.stButton > button {
227
+ color: #ffffff; /* Text color */
228
+ font-size: 30px; /* Font size */
229
+ background-image: linear-gradient(to right, #800000, #ff0000); /* Maroon to light red gradient */
230
+ border: none;
231
+ padding: 20px 20px; /* Increased vertical padding, horizontal padding stays the same */
232
+ cursor: pointer;
233
+ border-radius: 15px;
234
+ display: inline-block;
235
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 8px 15px rgba(0, 0, 0, 0.1); /* Box shadow */
236
+ transition: all 0.3s ease; /* Smooth transition on hover */
237
+ }
238
+ div.stButton > button:hover {
239
+ background-color: #00ff00; /* Hover background color */
240
+ color: #ff0000; /* Hover text color */
241
+ box-shadow: 0 6px 10px rgba(0, 0, 0, 0.2), 0 12px 20px rgba(0, 0, 0, 0.2); /* Box shadow on hover */
242
+ }
243
+ </style>
244
+ """
245
+
246
+
247
+ tooltip_message_bq = """
248
+ <div style="
249
+ font-size: 20px;
250
+ color: #716d6d;
251
+ margin-top: -10px;
252
+ margin-bottom: 20px;">
253
+ This UI allows you to upload CSV or Excel files and export their contents to a specified BigQuery table.
254
+ </div>
255
+ """
256
+
257
+ tooltip_message_fynd = """
258
+ <div style="
259
+ font-size: 20px;
260
+ color: #716d6d;
261
+ margin-top: -10px;
262
+ margin-bottom: 20px;">
263
+ This UI allows you to download month-wise Invoices.
264
+ </div>
265
+ """
266
+
267
+
268
+ tooltip_message_slack = """
269
+ <div style="
270
+ font-size: 20px;
271
+ color: #716d6d;
272
+ margin-top: -10px;
273
+ margin-bottom: 20px;">
274
+ This UI allows you to send Slack messages/emails to the selected channel members.
275
+ </div>
276
+ """
277
+
278
+
279
+ tooltip_message_tds = """
280
+ <div style="
281
+ font-size: 20px;
282
+ color: #716d6d;
283
+ margin-top: -10px;
284
+ margin-bottom: 20px;">
285
+ This page will help you to submit the TDS workings for TDS deductions made by your company for Shopsense Retail Technologies Limited (Fynd). Further this tool will reconcile your data with 26AS and will share you the report for the same.
286
+ </div>
287
+ """
288
+
289
+
290
+
291
+ tooltip_message_recon = """
292
+ <div style="
293
+ font-size: 20px;
294
+ color: #716d6d;
295
+ margin-top: -10px;
296
+ margin-bottom: 20px;">
297
+ This UI allows you to check duplicates in Recon pipeline.
298
+ </div>
299
+ """
300
+
301
+
302
+ invoice_splitter_title = """
303
+ <style>
304
+ .fixed-title {
305
+ font-size: 40px;
306
+ color: #ffffff;
307
+ background-image: linear-gradient(to right, #ff0000, #ffdab9);
308
+ background-clip: text;
309
+ -webkit-background-clip: text;
310
+ text-fill-color: transparent;
311
+ -webkit-text-fill-color: transparent;
312
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.4);
313
+ }
314
+ </style>
315
+ <h1 class="fixed-title">Invoice splitter</h1>
316
+ """
317
+
318
+ tooltip_message_splitter = """
319
+ <div style="
320
+ font-size: 20px;
321
+ color: #716d6d;
322
+ margin-top: -10px;
323
+ margin-bottom: 20px;">
324
+ This UI allows you to split CSV/Excel files as per the Invoice number written in the data.
325
+ </div>
326
+ """
327
+
328
+
329
+ tooltip_message_merger = """
330
+ <div style="
331
+ font-size: 20px;
332
+ color: #716d6d;
333
+ margin-top: -10px;
334
+ margin-bottom: 20px;">
335
+ This UI allows you to merge multiple CSV/Excel files.
336
+ </div>
337
+ """
338
+
339
+ download_button_styles = """
340
+ <style>
341
+ div.stDownloadButton > button {
342
+ color: #ffffff; /* Text color */
343
+ font-size: 30px;
344
+ background-image: linear-gradient(to right, #800000, #ff0000); /* Maroon to light red gradient */
345
+ border: none;
346
+ padding: 10px 20px;
347
+ cursor: pointer;
348
+ border-radius: 15px;
349
+ display: inline-block;
350
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 8px 15px rgba(0, 0, 0, 0.1); /* Box shadow */
351
+ transition: all 0.3s ease; /* Smooth transition on hover */
352
+ }
353
+ div.stDownloadButton > button:hover {
354
+ background-color: #00ff00; /* Hover background color */
355
+ color: #ff0000; /* Hover text color */
356
+ box-shadow: 0 6px 10px rgba(0, 0, 0, 0.2), 0 12px 20px rgba(0, 0, 0, 0.2); /* Box shadow on hover */
357
+ }
358
+ </style>
359
+ """
360
+ Slack_title = """
361
+ <style>
362
+ .fixed-title {
363
+ font-size: 40px;
364
+ color: #ffffff;
365
+ background-image: linear-gradient(to right, #ff0000, #ffdab9);
366
+ background-clip: text;
367
+ -webkit-background-clip: text;
368
+ text-fill-color: transparent;
369
+ -webkit-text-fill-color: transparent;
370
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.4);
371
+ }
372
+ </style>
373
+ <h1 class="fixed-title">Slack Integration</h1>
374
+ """
375
+
376
+
377
+
378
+ slack_message_title = """
379
+ <html>
380
+ <head>
381
+ <style>
382
+ .button {
383
+ display: inline-block;
384
+ padding: 10px 20px;
385
+ border-radius: 12px;
386
+ background: linear-gradient(to bottom, #f8f9fa, #e0e0e0);
387
+ box-shadow:
388
+ 0 6px 12px rgba(0, 0, 0, 0.3),
389
+ 0 8px 16px rgba(0, 0, 0, 0.2),
390
+ inset 0 -2px 4px rgba(255, 255, 255, 0.6);
391
+ text-align: center;
392
+ position: relative;
393
+ transform: translateY(4px);
394
+ transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
395
+ cursor: pointer;
396
+ user-select: none;
397
+ }
398
+ .button:hover {
399
+ box-shadow:
400
+ 0 8px 16px rgba(0, 0, 0, 0.3),
401
+ 0 12px 24px rgba(0, 0, 0, 0.2);
402
+ transform: translateY(2px);
403
+ }
404
+ .button:active {
405
+ box-shadow:
406
+ 0 4px 8px rgba(0, 0, 0, 0.3),
407
+ 0 6px 12px rgba(0, 0, 0, 0.2);
408
+ transform: translateY(0);
409
+ }
410
+ </style>
411
+ </head>
412
+ <body>
413
+ <div class="button">
414
+ <h3 style="
415
+ font-size: 20px;
416
+ color: #ffffff;
417
+ background-image: linear-gradient(to right, #800000, #ff0000, #ffdab9);
418
+ background-clip: text;
419
+ -webkit-background-clip: text;
420
+ text-fill-color: transparent;
421
+ -webkit-text-fill-color: transparent;
422
+ margin: 0;
423
+ text-shadow: 0 2px 5px rgba(0, 0, 0, 0.4);
424
+ ">Write a Slack message</h3>
425
+ </div>
426
+ </body>
427
+ </html>
428
+ """
429
+
430
+
431
+ upload_doc_title = """
432
+ <html>
433
+ <head>
434
+ <style>
435
+ .button {
436
+ display: inline-block;
437
+ padding: 10px 20px;
438
+ border-radius: 12px;
439
+ background: linear-gradient(to bottom, #f8f9fa, #e0e0e0);
440
+ box-shadow:
441
+ 0 6px 12px rgba(0, 0, 0, 0.3),
442
+ 0 8px 16px rgba(0, 0, 0, 0.2),
443
+ inset 0 -2px 4px rgba(255, 255, 255, 0.6);
444
+ text-align: center;
445
+ position: relative;
446
+ transform: translateY(4px);
447
+ transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
448
+ cursor: pointer;
449
+ user-select: none;
450
+ }
451
+ .button:hover {
452
+ box-shadow:
453
+ 0 8px 16px rgba(0, 0, 0, 0.3),
454
+ 0 12px 24px rgba(0, 0, 0, 0.2);
455
+ transform: translateY(2px);
456
+ }
457
+ .button:active {
458
+ box-shadow:
459
+ 0 4px 8px rgba(0, 0, 0, 0.3),
460
+ 0 6px 12px rgba(0, 0, 0, 0.2);
461
+ transform: translateY(0);
462
+ }
463
+ </style>
464
+ </head>
465
+ <body>
466
+ <div class="button">
467
+ <h3 style="
468
+ font-size: 20px;
469
+ color: #ffffff;
470
+ background-image: linear-gradient(to right, #800000, #ff0000, #ffdab9);
471
+ background-clip: text;
472
+ -webkit-background-clip: text;
473
+ text-fill-color: transparent;
474
+ -webkit-text-fill-color: transparent;
475
+ margin: 0;
476
+ text-shadow: 0 2px 5px rgba(0, 0, 0, 0.4);
477
+ ">Upload documents</h3>
478
+ </div>
479
+ </body>
480
+ </html>
481
+ """
482
+
483
+ channel_member_title = """
484
+ <html>
485
+ <head>
486
+ <style>
487
+ .button {
488
+ display: inline-block;
489
+ padding: 10px 20px;
490
+ border-radius: 12px;
491
+ background: linear-gradient(to bottom, #f8f9fa, #e0e0e0);
492
+ box-shadow:
493
+ 0 6px 12px rgba(0, 0, 0, 0.3),
494
+ 0 8px 16px rgba(0, 0, 0, 0.2),
495
+ inset 0 -2px 4px rgba(255, 255, 255, 0.6);
496
+ text-align: center;
497
+ position: relative;
498
+ transform: translateY(4px);
499
+ transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
500
+ cursor: pointer;
501
+ user-select: none;
502
+ }
503
+ .button:hover {
504
+ box-shadow:
505
+ 0 8px 16px rgba(0, 0, 0, 0.3),
506
+ 0 12px 24px rgba(0, 0, 0, 0.2);
507
+ transform: translateY(2px);
508
+ }
509
+ .button:active {
510
+ box-shadow:
511
+ 0 4px 8px rgba(0, 0, 0, 0.3),
512
+ 0 6px 12px rgba(0, 0, 0, 0.2);
513
+ transform: translateY(0);
514
+ }
515
+ </style>
516
+ </head>
517
+ <body>
518
+ <div class="button">
519
+ <h3 style="
520
+ font-size: 20px;
521
+ color: #ffffff;
522
+ background-image: linear-gradient(to right, #800000, #ff0000, #ffdab9);
523
+ background-clip: text;
524
+ -webkit-background-clip: text;
525
+ text-fill-color: transparent;
526
+ -webkit-text-fill-color: transparent;
527
+ margin: 0;
528
+ text-shadow: 0 2px 5px rgba(0, 0, 0, 0.4);
529
+ ">Select channels/members</h3>
530
+ </div>
531
+ </body>
532
+ </html>
533
+ """
534
+
535
+
536
+ email_subject = """
537
+ <html>
538
+ <head>
539
+ <style>
540
+ .button {
541
+ display: inline-block;
542
+ padding: 10px 20px;
543
+ border-radius: 12px;
544
+ background: linear-gradient(to bottom, #f8f9fa, #e0e0e0);
545
+ box-shadow:
546
+ 0 6px 12px rgba(0, 0, 0, 0.3),
547
+ 0 8px 16px rgba(0, 0, 0, 0.2),
548
+ inset 0 -2px 4px rgba(255, 255, 255, 0.6);
549
+ text-align: center;
550
+ position: relative;
551
+ transform: translateY(4px);
552
+ transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
553
+ cursor: pointer;
554
+ user-select: none;
555
+ }
556
+ .button:hover {
557
+ box-shadow:
558
+ 0 8px 16px rgba(0, 0, 0, 0.3),
559
+ 0 12px 24px rgba(0, 0, 0, 0.2);
560
+ transform: translateY(2px);
561
+ }
562
+ .button:active {
563
+ box-shadow:
564
+ 0 4px 8px rgba(0, 0, 0, 0.3),
565
+ 0 6px 12px rgba(0, 0, 0, 0.2);
566
+ transform: translateY(0);
567
+ }
568
+ </style>
569
+ </head>
570
+ <body>
571
+ <div class="button">
572
+ <h3 style="
573
+ font-size: 20px;
574
+ color: #ffffff;
575
+ background-image: linear-gradient(to right, #800000, #ff0000, #ffdab9);
576
+ background-clip: text;
577
+ -webkit-background-clip: text;
578
+ text-fill-color: transparent;
579
+ -webkit-text-fill-color: transparent;
580
+ margin: 0;
581
+ text-shadow: 0 2px 5px rgba(0, 0, 0, 0.4);
582
+ ">Enter the subject(optional)</h3>
583
+ </div>
584
+ </body>
585
+ </html>
586
+ """
587
+
588
+ email_body = """
589
+ <html>
590
+ <head>
591
+ <style>
592
+ .button {
593
+ display: inline-block;
594
+ padding: 10px 20px;
595
+ border-radius: 12px;
596
+ background: linear-gradient(to bottom, #f8f9fa, #e0e0e0);
597
+ box-shadow:
598
+ 0 6px 12px rgba(0, 0, 0, 0.3),
599
+ 0 8px 16px rgba(0, 0, 0, 0.2),
600
+ inset 0 -2px 4px rgba(255, 255, 255, 0.6);
601
+ text-align: center;
602
+ position: relative;
603
+ transform: translateY(4px);
604
+ transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
605
+ cursor: pointer;
606
+ user-select: none;
607
+ }
608
+ .button:hover {
609
+ box-shadow:
610
+ 0 8px 16px rgba(0, 0, 0, 0.3),
611
+ 0 12px 24px rgba(0, 0, 0, 0.2);
612
+ transform: translateY(2px);
613
+ }
614
+ .button:active {
615
+ box-shadow:
616
+ 0 4px 8px rgba(0, 0, 0, 0.3),
617
+ 0 6px 12px rgba(0, 0, 0, 0.2);
618
+ transform: translateY(0);
619
+ }
620
+ </style>
621
+ </head>
622
+ <body>
623
+ <div class="button">
624
+ <h3 style="
625
+ font-size: 20px;
626
+ color: #ffffff;
627
+ background-image: linear-gradient(to right, #800000, #ff0000, #ffdab9);
628
+ background-clip: text;
629
+ -webkit-background-clip: text;
630
+ text-fill-color: transparent;
631
+ -webkit-text-fill-color: transparent;
632
+ margin: 0;
633
+ text-shadow: 0 2px 5px rgba(0, 0, 0, 0.4);
634
+ ">Enter the body (optional)</h3>
635
+ </div>
636
+ </body>
637
+ </html>
638
+ """
639
+
640
+ email_title = """
641
+ <html>
642
+ <head>
643
+ <style>
644
+ .button {
645
+ display: inline-block;
646
+ padding: 10px 20px;
647
+ border-radius: 12px;
648
+ background: linear-gradient(to bottom, #f8f9fa, #e0e0e0);
649
+ box-shadow:
650
+ 0 6px 12px rgba(0, 0, 0, 0.3),
651
+ 0 8px 16px rgba(0, 0, 0, 0.2),
652
+ inset 0 -2px 4px rgba(255, 255, 255, 0.6);
653
+ text-align: center;
654
+ position: relative;
655
+ transform: translateY(4px);
656
+ transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
657
+ cursor: pointer;
658
+ user-select: none;
659
+ }
660
+ .button:hover {
661
+ box-shadow:
662
+ 0 8px 16px rgba(0, 0, 0, 0.3),
663
+ 0 12px 24px rgba(0, 0, 0, 0.2);
664
+ transform: translateY(2px);
665
+ }
666
+ .button:active {
667
+ box-shadow:
668
+ 0 4px 8px rgba(0, 0, 0, 0.3),
669
+ 0 6px 12px rgba(0, 0, 0, 0.2);
670
+ transform: translateY(0);
671
+ }
672
+ </style>
673
+ </head>
674
+ <body>
675
+ <div class="button">
676
+ <h3 style="
677
+ font-size: 20px;
678
+ color: #ffffff;
679
+ background-image: linear-gradient(to right, #800000, #ff0000, #ffdab9);
680
+ background-clip: text;
681
+ -webkit-background-clip: text;
682
+ text-fill-color: transparent;
683
+ -webkit-text-fill-color: transparent;
684
+ margin: 0;
685
+ text-shadow: 0 2px 5px rgba(0, 0, 0, 0.4);
686
+ ">Enter the email address(es)</h3>
687
+ </div>
688
+ </body>
689
+ </html>
690
+ """
691
+
692
+ tooltip_message_gmail = """
693
+ <div style="
694
+ font-size: 16px;
695
+ color: #716d6d;
696
+ margin-top: -10px;
697
+ margin-bottom: 20px;">
698
+ In case of multiple email addresses, please write them comma-separated.
699
+ E.g. abc@gmail.com, def@gmail.com
700
+ </div>
701
+ """
702
+
703
+
704
+ spinner_css = """
705
+ <style>
706
+ /* Apply gradient to the spinner's text */
707
+ .stSpinner .stSpin div {
708
+ color: transparent !important; /* Make text transparent */
709
+ -webkit-background-clip: text !important; /* Clip background to the text */
710
+ background: linear-gradient(to right, #800000, #ff0000) !important; /* Gradient for text */
711
+ font-weight: bold !important; /* Bold text */
712
+ }
713
+
714
+ /* Apply gradient to the spinner circle */
715
+ .stSpinner .stSpin::before {
716
+ border: 6px solid transparent !important;
717
+ border-top: 6px solid transparent !important;
718
+ border-left: 6px solid transparent !important;
719
+ border-bottom: 6px solid transparent !important;
720
+ border-radius: 50% !important;
721
+ border-top: 6px solid linear-gradient(to right, #800000, #ff0000) !important; /* Gradient for spinner circle */
722
+ animation: spin 1s linear infinite !important;
723
+ }
724
+
725
+ /* Keyframe animation for spinner rotation */
726
+ @keyframes spin {
727
+ 0% {
728
+ transform: rotate(0deg);
729
+ }
730
+ 100% {
731
+ transform: rotate(360deg);
732
+ }
733
+ }
734
+ </style>
735
+ """
736
+
737
+
738
+ recon_title = """
739
+ <style>
740
+ .fixed-title {
741
+ font-size: 40px;
742
+ color: #ffffff;
743
+ background-image: linear-gradient(to right, #ff0000, #ffdab9);
744
+ background-clip: text;
745
+ -webkit-background-clip: text;
746
+ text-fill-color: transparent;
747
+ -webkit-text-fill-color: transparent;
748
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.4);
749
+ }
750
+ </style>
751
+ <h1 class="fixed-title">Recon validation</h1>
752
+ """
753
+
754
+
755
+ duplicate_count = """
756
+ <html>
757
+ <head>
758
+ <style>
759
+ .button {
760
+ display: inline-block;
761
+ padding: 10px 20px;
762
+ border-radius: 12px;
763
+ background: linear-gradient(to bottom, #f8f9fa, #e0e0e0);
764
+ box-shadow:
765
+ 0 6px 12px rgba(0, 0, 0, 0.3),
766
+ 0 8px 16px rgba(0, 0, 0, 0.2),
767
+ inset 0 -2px 4px rgba(255, 255, 255, 0.6);
768
+ text-align: center;
769
+ position: relative;
770
+ transform: translateY(4px);
771
+ transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
772
+ cursor: pointer;
773
+ user-select: none;
774
+ }
775
+ .button:hover {
776
+ box-shadow:
777
+ 0 8px 16px rgba(0, 0, 0, 0.3),
778
+ 0 12px 24px rgba(0, 0, 0, 0.2);
779
+ transform: translateY(2px);
780
+ }
781
+ .button:active {
782
+ box-shadow:
783
+ 0 4px 8px rgba(0, 0, 0, 0.3),
784
+ 0 6px 12px rgba(0, 0, 0, 0.2);
785
+ transform: translateY(0);
786
+ }
787
+ .spacing {
788
+ margin: 20px 0; /* Adjust the value as needed */
789
+ }
790
+ .result-box {
791
+ border: 1px solid #ddd;
792
+ border-radius: 8px;
793
+ background: #f9f9f9;
794
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
795
+ padding: 10px;
796
+ margin-bottom: 10px;
797
+ font-size: 16px;
798
+ }
799
+ .result-title {
800
+ font-weight: bold;
801
+ color: #333;
802
+ }
803
+ </style>
804
+ </head>
805
+ <body>
806
+ <div class="button">
807
+ <h3 style="
808
+ font-size: 20px;
809
+ color: #ffffff;
810
+ background-image: linear-gradient(to right, #800000, #ff0000, #ffdab9);
811
+ background-clip: text;
812
+ -webkit-background-clip: text;
813
+ text-fill-color: transparent;
814
+ -webkit-text-fill-color: transparent;
815
+ margin: 0;
816
+ text-shadow: 0 2px 5px rgba(0, 0, 0, 0.4);
817
+ ">Duplicate Counts for Queries:</h3>
818
+ </div>
819
+ <div class="spacing"></div> <!-- Adds spacing between the heading and the content -->
820
+ </body>
821
+ </html>
822
+ """
823
+
824
+
825
+ template_file_title = """
826
+ <html>
827
+ <head>
828
+ <style>
829
+ .button {
830
+ display: inline-block;
831
+ padding: 10px 20px;
832
+ border-radius: 12px;
833
+ background: linear-gradient(to bottom, #f8f9fa, #e0e0e0);
834
+ box-shadow:
835
+ 0 6px 12px rgba(0, 0, 0, 0.3),
836
+ 0 8px 16px rgba(0, 0, 0, 0.2),
837
+ inset 0 -2px 4px rgba(255, 255, 255, 0.6);
838
+ text-align: center;
839
+ position: relative;
840
+ transform: translateY(4px);
841
+ transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
842
+ cursor: pointer;
843
+ user-select: none;
844
+ }
845
+ .button:hover {
846
+ box-shadow:
847
+ 0 8px 16px rgba(0, 0, 0, 0.3),
848
+ 0 12px 24px rgba(0, 0, 0, 0.2);
849
+ transform: translateY(2px);
850
+ }
851
+ .button:active {
852
+ box-shadow:
853
+ 0 4px 8px rgba(0, 0, 0, 0.3),
854
+ 0 6px 12px rgba(0, 0, 0, 0.2);
855
+ transform: translateY(0);
856
+ }
857
+ </style>
858
+ </head>
859
+ <body>
860
+ <div class="button">
861
+ <h3 style="
862
+ font-size: 20px;
863
+ color: #ffffff;
864
+ background-image: linear-gradient(to right, #800000, #ff0000, #ffdab9);
865
+ background-clip: text;
866
+ -webkit-background-clip: text;
867
+ text-fill-color: transparent;
868
+ -webkit-text-fill-color: transparent;
869
+ margin: 0;
870
+ text-shadow: 0 2px 5px rgba(0, 0, 0, 0.4);
871
+ ">Download the template file</h3>
872
+ </div>
873
+ </body>
874
+ </html>
875
+ """
876
+
877
+
878
+ upload_tds_file = """
879
+ <html>
880
+ <head>
881
+ <style>
882
+ .button {
883
+ display: inline-block;
884
+ padding: 10px 20px;
885
+ border-radius: 12px;
886
+ background: linear-gradient(to bottom, #f8f9fa, #e0e0e0);
887
+ box-shadow:
888
+ 0 6px 12px rgba(0, 0, 0, 0.3),
889
+ 0 8px 16px rgba(0, 0, 0, 0.2),
890
+ inset 0 -2px 4px rgba(255, 255, 255, 0.6);
891
+ text-align: center;
892
+ position: relative;
893
+ transform: translateY(4px);
894
+ transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
895
+ cursor: pointer;
896
+ user-select: none;
897
+ }
898
+ .button:hover {
899
+ box-shadow:
900
+ 0 8px 16px rgba(0, 0, 0, 0.3),
901
+ 0 12px 24px rgba(0, 0, 0, 0.2);
902
+ transform: translateY(2px);
903
+ }
904
+ .button:active {
905
+ box-shadow:
906
+ 0 4px 8px rgba(0, 0, 0, 0.3),
907
+ 0 6px 12px rgba(0, 0, 0, 0.2);
908
+ transform: translateY(0);
909
+ }
910
+ </style>
911
+ </head>
912
+ <body>
913
+ <div class="button">
914
+ <h3 style="
915
+ font-size: 20px;
916
+ color: #ffffff;
917
+ background-image: linear-gradient(to right, #800000, #ff0000, #ffdab9);
918
+ background-clip: text;
919
+ -webkit-background-clip: text;
920
+ text-fill-color: transparent;
921
+ -webkit-text-fill-color: transparent;
922
+ margin: 0;
923
+ text-shadow: 0 2px 5px rgba(0, 0, 0, 0.4);
924
+ ">Upload the TDS file</h3>
925
+ </div>
926
+ </body>
927
+ </html>
928
+ """
payment_queries.py ADDED
@@ -0,0 +1,332 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ queries = {
3
+ # Query 1
4
+ '1. Duplicate data in 09_payable_file': '''
5
+ select
6
+ merged,
7
+ count(merged)
8
+ from
9
+ `fynd-db.Outstanding.09_Payable_File_table` as A
10
+ group by
11
+ 1
12
+ having
13
+ count(merged) <> 1
14
+ ''',
15
+
16
+ '2. Checking already paid data showing in outstanding file': '''
17
+ select
18
+ merged,
19
+ paid_settled_merged_transaction,
20
+ REGEXP_CONTAINS(paid_settled_merged_transaction, CONCAT(r'(^|,)', merged, r'(,|$)')) as cc1,
21
+ from
22
+ `fynd-db.Outstanding.09_Payable_File_table` as A
23
+ where
24
+ REGEXP_CONTAINS(paid_settled_merged_transaction, CONCAT(r'(^|,)', merged, r'(,|$)')) <> false
25
+ ''',
26
+
27
+
28
+ '3. Checking return transaction not having sale transaction': '''
29
+ select
30
+ bag_id,
31
+ paid_settled_merged_transaction,
32
+ count(bag_id) as bag_count,
33
+ from
34
+ `fynd-db.Outstanding.09_Payable_File_table`
35
+ where
36
+ bag_id in
37
+ (select
38
+ bag_id,
39
+ -- merged,
40
+ -- paid_settled_merged_transaction,
41
+ -- REGEXP_CONTAINS(paid_settled_merged_transaction, CONCAT(r'(^|,)', merged, r'(,|$)')) as cc1,
42
+ from
43
+ `fynd-db.Outstanding.09_Payable_File_table` as A
44
+ where
45
+ transaction_type = 'Return'
46
+ and paid_settled_merged_transaction is null)
47
+ group by
48
+ 1,2
49
+ having
50
+ count(bag_id) = 1
51
+ order by
52
+ 1 asc
53
+ ''',
54
+
55
+
56
+ '4. Checking old data inserted in 09_net_collection table': '''
57
+ SELECT
58
+ A.bag_id,
59
+ A.collection_partner,
60
+ A.Settlement_type,
61
+ A.inserted_date,
62
+ B.bag_id,
63
+ B.Transaction_type,
64
+ C.bag_id,
65
+ C.settlement_type,
66
+ D.bag_id
67
+ FROM
68
+ `fynd-db.finance_recon_tool_asia.01_finance_avis_data_final` AS A
69
+ LEFT JOIN
70
+ `fynd-db.finance_dwh.Brand_Settlement_pulse` AS B
71
+ ON A.bag_id = B.bag_id
72
+ LEFT JOIN
73
+ `fynd-db.finance_recon_tool_asia.09_seller_net_collection_daily` AS C
74
+ ON A.bag_id = C.bag_id
75
+ LEFT JOIN
76
+ `fynd-db.finance_recon_tool_asia.05_partner_collection` AS D
77
+ ON A.bag_id = D.bag_id
78
+ WHERE
79
+ A.Settlement_type <> 'NA'
80
+ and date(A.inserted_date) > '2024-07-31'
81
+ AND B.bag_id IS NOT NULL
82
+ AND C.bag_id IS NOT NULL
83
+ AND D.bag_id IS NOT NULL
84
+ AND (
85
+ CASE
86
+ WHEN A.Settlement_type = 'collection' THEN 'Sale'
87
+ WHEN A.Settlement_type = 'refund' THEN 'Return'
88
+ ELSE 'Claim'
89
+ END
90
+ ) = B.Transaction_type
91
+ GROUP BY
92
+ 1,2,3,4,5,6,7,8,9
93
+ ''',
94
+
95
+
96
+ '5. Checking whether expected payout date is null': '''
97
+ SELECT
98
+ *
99
+ FROM
100
+ `fynd-db.Outstanding.09_Payable_File_table`
101
+ where
102
+ expected_payout_date is null
103
+ ''',
104
+
105
+ '6. Validation for seller net collection formula': '''
106
+ SELECT
107
+ distinct
108
+ bag_id,
109
+ transaction_type,
110
+ settlement_type,
111
+ round(esp-seller_discounts-bca,0) BCA_Diff,
112
+ round(bca-seller_tender_value-tcs_on_vog-tds_on_bca+seller_fees-seller_net_collection,0) Seller_net_collection_diff
113
+ FROM
114
+ `fynd-db.Outstanding.09_Payable_File_table`
115
+ where
116
+ round(esp-seller_discounts-bca,0) not in (0,1)
117
+ and round(bca-seller_tender_value-tcs_on_vog-tds_on_bca+seller_fees-seller_net_collection,0) not in (0,1)
118
+ ''',
119
+
120
+ '7. Checking sign for payout, refund & claim ': '''
121
+ SELECT
122
+ *,
123
+ CASE
124
+ WHEN (settlement_type = 'collection' AND bca >= 0) THEN 'MATCH'
125
+ WHEN (settlement_type = 'refund' AND bca <= 0) THEN 'MATCH'
126
+ WHEN (settlement_type = 'Claim' AND bca >= 0) THEN 'MATCH'
127
+ ELSE 'NOT MATCH'
128
+ END AS comment
129
+ FROM
130
+ `fynd-db.Outstanding.09_Payable_File_table`
131
+ WHERE
132
+ --settlement_type ='collection' and
133
+ settlement_type in ('collection','refund','cliam') and
134
+ NOT (
135
+ (settlement_type = 'collection' AND bca >= 0)
136
+ OR
137
+ (settlement_type = 'refund' AND bca <= 0)
138
+ OR
139
+ (settlement_type = 'claim' AND bca >= 0)
140
+ )
141
+ ''',
142
+
143
+ '8. Checking TCS & TDS': '''
144
+ SELECT
145
+ distinct
146
+ bag_id,
147
+ settlement_type,
148
+ segement_code,
149
+ tcs_on_vog,
150
+ tds_on_bca,
151
+ case when segement_code not in ('FY','UN') and tcs_on_vog = 0 then 'Match'
152
+ when segement_code not in ('FY','UN') and tds_on_bca = 0 then 'Match'
153
+ when segement_code in ('FY','UN') and tcs_on_vog <> 0 and tds_on_bca <> 0 then 'Match' else "Not Match" end as Check
154
+ FROM
155
+ `fynd-db.Outstanding.09_Payable_File_table`
156
+ where
157
+ (case when segement_code not in ('FY','UN') and tcs_on_vog = 0 then 'Match'
158
+ when segement_code not in ('FY','UN') and tds_on_bca = 0 then 'Match'
159
+ when segement_code in ('FY','UN') and tcs_on_vog <> 0 and tds_on_bca <> 0 then 'Match' else "Not Match" end) = 'Not Match'
160
+ ''',
161
+
162
+
163
+ '9. Collection done but data not updated in 09_net_collection': '''
164
+ with status as (SELECT
165
+ Company_id,
166
+ Company_name,
167
+ Bagid,
168
+ Placed_date,
169
+ Cancelled_date,
170
+ bag_invoiced,
171
+ RTO_delivered_date,
172
+ Delivered_date,
173
+ FROM
174
+ `fynd-db.finance_asia_dwh.Bag_Audit_review`),
175
+ error_bags as (
176
+ SELECT
177
+ bag_id
178
+ FROM `fynd-db.finance_recon_tool_asia.03_error_view_data`
179
+ WHERE
180
+ resolve_date is null
181
+ )
182
+ SELECT
183
+ DISTINCT
184
+ C.Company_id,
185
+ C.Company_name,
186
+ A.bag_id AS COLLECTED_BAG,
187
+ B.bag_id AS SETTLEMENT_BAG,
188
+ D.bag_id AS error_BAG,
189
+ A.order_type,
190
+ Placed_date,
191
+ Cancelled_date,
192
+ bag_invoiced,
193
+ RTO_delivered_date,
194
+ Delivered_date
195
+ FROM
196
+ `fynd-db.finance_recon_tool_asia.05_partner_collection` AS A
197
+ left join
198
+ (SELECT
199
+ DISTINCT
200
+ bag_id
201
+ FROM `fynd-db.finance_recon_tool_asia.09_seller_net_collection_daily`
202
+ WHERE
203
+ Settlement_type = 'collection'
204
+ ) AS B
205
+ ON
206
+ A.bag_id = B.bag_id
207
+ left join
208
+ status as C
209
+ on
210
+ A.bag_id = C.Bagid
211
+ left join
212
+ error_bags as D
213
+ on
214
+ A.bag_id = D.bag_id
215
+ WHERE
216
+ receipt_date >= '2023-04-01'
217
+ and net_remitted <> 0
218
+ and C.Company_id not in (select
219
+ test_company
220
+ from `fynd-db.finance_dwh.test_details`)
221
+ AND B.bag_id IS NULL
222
+ and Delivered_date is not null
223
+ AND D.bag_id IS NULL
224
+ ''',
225
+
226
+ '10. Refund done but data not updated in 09_net_collection': '''
227
+ with status as (SELECT
228
+ Company_id,
229
+ Company_name,
230
+ Ordering_channel,
231
+ Bagid,
232
+ Placed_date,
233
+ Cancelled_date,
234
+ bag_invoiced,
235
+ RTO_delivered_date,
236
+ Delivered_date,
237
+ Return_picked_date,
238
+ Return_delivered_date
239
+ FROM
240
+ `fynd-db.finance_asia_dwh.Bag_Audit_review`),
241
+ error_bags as (
242
+ SELECT
243
+ bag_id
244
+ FROM `fynd-db.finance_recon_tool_asia.03_error_view_data`
245
+ WHERE
246
+ resolve_date is null
247
+ )
248
+ SELECT
249
+ DISTINCT
250
+ C.Company_id,
251
+ C.Company_name,
252
+ C.Ordering_channel,
253
+ A.bag_id AS COLLECTED_BAG,
254
+ B.bag_id AS SETTLEMENT_BAG,
255
+ D.bag_id AS error_BAG,
256
+ A.order_type,
257
+ Placed_date,
258
+ Cancelled_date,
259
+ bag_invoiced,
260
+ RTO_delivered_date,
261
+ Delivered_date,
262
+ Return_picked_date,
263
+ Return_delivered_date
264
+ FROM
265
+ `fynd-db.finance_recon_tool_asia.05_partner_refunds` AS A
266
+ left join
267
+ (SELECT
268
+ DISTINCT
269
+ bag_id
270
+ FROM `fynd-db.finance_recon_tool_asia.09_seller_net_collection_daily`
271
+ WHERE
272
+ Settlement_type = 'refund'
273
+ ) AS B
274
+ ON
275
+ A.bag_id = B.bag_id
276
+ left join
277
+ status as C
278
+ on
279
+ A.bag_id = C.Bagid
280
+ left join
281
+ error_bags as D
282
+ on
283
+ A.bag_id = D.bag_id
284
+ WHERE
285
+ refund_date >= '2023-04-01'
286
+ and net_refunded <> 0
287
+ and C.Company_id not in (select
288
+ test_company
289
+ from `fynd-db.finance_dwh.test_details`)
290
+ AND B.bag_id IS NULL
291
+ and C.Company_id not in (507)
292
+ and (case when Ordering_channel in ('FYND','UNIKET') and Return_picked_date is not null then 'yes'
293
+ when Ordering_channel not in ('FYND','UNIKET') and Return_delivered_date is not null then 'yes' else 'no' end) = 'yes'
294
+ AND D.bag_id IS NULL
295
+ ''',
296
+
297
+
298
+ '11. Checking for duplicate count in 09_net_collection': '''
299
+ select
300
+ concat(bag_id,Settlement_type) as Merged,
301
+ count(concat(bag_id,Settlement_type))
302
+ from `fynd-db.finance_recon_tool_asia.09_seller_net_collection_daily`
303
+ group by
304
+ 1
305
+ having
306
+ count(concat(bag_id,Settlement_type)) not in (1)
307
+ ''',
308
+
309
+ '12. Checking for presence of Non-RBL, Prepaid & Fynd/Uniket in 09_payable_file': '''
310
+ select
311
+ *
312
+ from
313
+ `fynd-db.Outstanding.09_Payable_File_table` A
314
+ where
315
+ order_type = 'PPD'
316
+ and
317
+ ordering_channel not in ('UNIKET', 'FYND')
318
+ and
319
+ A.Company_Type = 'Non RBL'
320
+ and collection_comment = 'collection_pending'
321
+ ''',
322
+
323
+ '13. Checking for difference in collection': '''
324
+ select
325
+ *,
326
+ current_timestamp() as table_update_date
327
+ from
328
+ `fynd-db.Outstanding.09_Payable_File_table`
329
+ where
330
+ Collection_amount_comment = 'collection_diff'
331
+ '''
332
+ }
plan_v2.template.csv ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ Business_Head,Company_ID,Company_Name,Currency,Bundle_by,Plan_Name,Plan_Description,Product_lines,Fulfilling_Location,Application_ID,Fee_Type,Variable_Type,Chargeable_on,Fee_Nature,Commercial_value,Fee_reversal,Reversal_%,Usage_limit,Threshold_value,Threshold_option,Expected_Billing,Plan_Validity,Payment_Method,rule_id,plan_id,created_at,Net_total_billing,slab_data,final_rule_id
2
+ Commerce India,2411,Cantabil Retail India Limited,INR,Feature specific,MP,MP plan,OMS,,,Transaction,Bag,Invoiced,Flat currency,3,,0,0,100000,Minimum Guarantee,100000,Monthly,Postpaid,00000_00_00_00_00_00_00_00_00,00000_a_000000,2024-11-18 06:43:20.171593 UTC,100000,,
queries.py ADDED
@@ -0,0 +1,558 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ queries = {
3
+ # Query 1
4
+ '1. fynd-db.finance_recon_tool_asia.01_finance_avis_data_final': '''
5
+ select
6
+ bag_id,
7
+ concat(bag_id,Recon_Status,Settlement_type,Transaction_Type) as Merged,
8
+ count(concat(bag_id,Recon_Status,Settlement_type,Transaction_Type))
9
+ from `fynd-db.finance_recon_tool_asia.01_finance_avis_data_final`
10
+ group by
11
+ 1,2
12
+ having count(concat(bag_id,Recon_Status,Settlement_type,Transaction_Type)) not in (1)
13
+ ''',
14
+
15
+ # Query 2
16
+ '2. Seller fees date validation': '''
17
+ select
18
+ *
19
+ from `fynd-db.finance_recon_tool_asia.11_seller_fees_daily`
20
+ where
21
+ invoice_generation_date is null
22
+ ''',
23
+
24
+
25
+ # Query 3
26
+ # '3. Checking 01_finance all data inserted into 11_seller_fees': '''
27
+ # with commission as (select
28
+ # bag_id,
29
+ # Transaction_Type,
30
+ # Commission_in_percent
31
+ # from
32
+ # `fynd-db.finance_recon_tool_asia.11_seller_fees_logic`
33
+ # group by
34
+ # 1,2,3
35
+ # )
36
+ # select
37
+ # A.company_id,
38
+ # A.company_name,
39
+ # A.ordering_channel,
40
+ # A.sales_channel,
41
+ # A.bag_id,
42
+ # A.transaction_type,
43
+ # A.recon_status,
44
+ # A.recon_date,
45
+ # A.return_window_date,
46
+ # A.payout_window_date,
47
+ # A.inserted_date,
48
+ # B.bag_id,
49
+ # B.transaction_type,
50
+ # C.Commission_in_percent
51
+ # from `fynd-db.finance_recon_tool_asia.01_finance_avis_data_final` as A
52
+ # left join
53
+ # `fynd-db.finance_recon_tool_asia.11_seller_fees_daily` as B
54
+ # on
55
+ # A.bag_id = B.bag_id
56
+ # and A.transaction_type = B.transaction_type
57
+ # left join
58
+ # commission as C
59
+ # on
60
+ # A.bag_id = C.bag_id
61
+ # and A.transaction_type = C.transaction_type
62
+ # where
63
+ # A.transaction_type not in ('NA','SLA')
64
+ # and B.bag_id is null
65
+ # and A.recon_status not in ("return_bag_lost","bag_lost","dispute","dispute_R")
66
+ # and A.sales_channel not in ('JIOMART',"Freshpik")
67
+ # and A.company_id <> 3138
68
+ # -- and C.Commission_in_percent <> 0
69
+ # group by
70
+ # 1,2,3,4,5,6,7,8,9,10,11,12,13,14
71
+ # ''',
72
+
73
+ # Query 3
74
+ '3. Transaction components validation': '''
75
+ select
76
+ bag_id,
77
+ transaction_type,
78
+ inserted_date,
79
+ round(transaction_fee+packaging_fee+logistics_charges+refund_support_fees+sla_charges-net_charges,0) as diff
80
+ from `fynd-db.finance_recon_tool_asia.11_seller_fees_daily`
81
+ where
82
+ round(transaction_fee+packaging_fee+logistics_charges+refund_support_fees+sla_charges-net_charges,0) not in (0,-1,-1)
83
+ and inserted_date > '2023-09-30'
84
+ group by 1,2,3, transaction_fee,packaging_fee,refund_support_fees,sla_charges,net_charges,logistics_charges
85
+ ''',
86
+
87
+ # Query 4
88
+ '4. Transactions in net collection validation': '''
89
+ select
90
+ concat(bag_id,Settlement_type) as Merged,
91
+ count(concat(bag_id,Settlement_type))
92
+ from `fynd-db.finance_recon_tool_asia.09_seller_net_collection_daily`
93
+ group by 1
94
+ having
95
+ count(concat(bag_id,Settlement_type)) not in (1)
96
+ ''',
97
+
98
+ # Query 5
99
+ '5. Transactions in seller fees validation': '''
100
+ select
101
+ bag_id,
102
+ concat(bag_id,transaction_type) as Merged,
103
+ count(concat(bag_id,transaction_type))
104
+ from `fynd-db.finance_recon_tool_asia.11_seller_fees_daily`
105
+ group by 1,2
106
+ having
107
+ count(concat(bag_id,transaction_type)) not in (1)
108
+ ''',
109
+
110
+
111
+ # Query 6
112
+ '6. Transactions in seller claims validation': '''
113
+ select
114
+ current_shipment_id,
115
+ concat(current_shipment_id,transaction_type) as Merged,
116
+ count(concat(current_shipment_id,transaction_type))
117
+ from `fynd-db.finance_recon_tool_asia.12_seller_claims_daily`
118
+ group by 1,2
119
+ having
120
+ count(concat(current_shipment_id,transaction_type)) not in (1)
121
+ ''',
122
+
123
+
124
+ # Query 7
125
+ '7. Aggregate liability validation': '''
126
+ select
127
+ *
128
+ from `fynd-db.finance_recon_tool_asia.12_seller_claims_daily`
129
+ where
130
+ aggregate_liability is null
131
+ ''',
132
+
133
+
134
+ # Query 8
135
+ '8. Lost claim validation': '''
136
+ select
137
+ *
138
+ from `fynd-db.finance_recon_tool_asia.01_finance_avis_data_final` as A
139
+ left join
140
+ `fynd-db.finance_recon_tool_asia.12_seller_claims_daily` as B
141
+ on
142
+ A.current_shipment_id = B.current_shipment_id
143
+ where
144
+ A.claim_settle_date is not null
145
+ and A.transaction_type = 'Claim'
146
+ and A.dp_partner = 'fynd'
147
+ and B.current_shipment_id is null
148
+ ''',
149
+
150
+
151
+
152
+ # Query 9
153
+ '9. Gstin validation': '''
154
+ select
155
+ company_id,
156
+ company_name,
157
+ ordering_channel
158
+ from `fynd-db.finance_recon_tool_asia.11_seller_fees_daily`
159
+ where
160
+ company_gstn is null
161
+ group by
162
+ 1,2,3
163
+ ''',
164
+
165
+
166
+
167
+ # Query 10
168
+ '10. Positive transaction components validation': '''
169
+ SELECT
170
+ CONCAT(bag_id,transaction_type,total_charges) AS Merged,
171
+ FROM
172
+ `fynd-db.finance_recon_tool_asia.11_seller_fees_daily`
173
+ GROUP BY
174
+ 1
175
+ HAVING
176
+ COUNT(CONCAT(bag_id,transaction_type)) NOT IN (1)
177
+ ''',
178
+
179
+
180
+ # Query 11
181
+ '11. Negative transaction components validation': '''
182
+ select
183
+ *
184
+ from `fynd-db.finance_recon_tool_asia.11_seller_fees_daily`
185
+ where
186
+ transaction_type = 'Return'
187
+ and net_charges < 0
188
+ ''',
189
+
190
+
191
+ # Query 12
192
+ '12. GST Tag validation': '''
193
+ select
194
+ company_id,
195
+ company_name,
196
+ ordering_channel,
197
+ company_gstn,
198
+ gst_tag,
199
+ case WHEN LENGTH(company_gstn) = 10 then "SGST"
200
+ when SUBSTRING(company_gstn,1,2) = '27' then "SGST" else "IGST" end as Tag,
201
+ case when gst_tag = (case WHEN LENGTH(company_gstn) = 10 then "SGST"
202
+ when SUBSTRING(company_gstn,1,2) = '27' then "SGST" else "IGST" end) then "Match" else "Not_Match" end as CC
203
+ from `fynd-db.finance_recon_tool_asia.11_seller_fees_daily`
204
+ where
205
+ (case when gst_tag = (case WHEN LENGTH(company_gstn) = 10 then "SGST"
206
+ when SUBSTRING(company_gstn,1,2) = '27' then "SGST" else "IGST" end) then "Match" else "Not_Match" end) = "Not_Match"
207
+ group by 1,2,3,4,5,6
208
+ ''',
209
+
210
+ # Query 13
211
+ '13. 09_Net collection all data validation': '''
212
+ select
213
+ A.company_id,
214
+ A.company_name,
215
+ A.ordering_channel,
216
+ A.bag_id,
217
+ A.Settlement_type,
218
+ A.recon_status,
219
+ A.recon_date,
220
+ A.inserted_date,
221
+ B.bag_id,
222
+ B.Settlement_type
223
+ from `fynd-db.finance_recon_tool_asia.01_finance_avis_data_final` as A
224
+ left join
225
+ `fynd-db.finance_recon_tool_asia.09_seller_net_collection_daily` as B
226
+ on
227
+ A.bag_id = B.bag_id
228
+ and A.Settlement_type = B.Settlement_type
229
+ where
230
+ A.Settlement_type not in ('NA','SLA')
231
+ and A.recon_status in ('delivery_done','return_bag_delivered','return_bag_picked')
232
+ and B.bag_id is null
233
+ and (case when A.Settlement_type = 'collection' and A.collection_partner = 'fynd' then 'yes'
234
+ when A.Settlement_type = 'refund' and A.refund_partner = 'fynd' then 'yes' else 'no' end) = 'yes'
235
+ group by
236
+ 1,2,3,4,5,6,7,8,9,10
237
+ ''',
238
+
239
+
240
+ # Query 14
241
+ '14. Net collection collection & refund validation': '''
242
+ select
243
+ bag_id,
244
+ settlement_type,
245
+ collection_partner,
246
+ refund_partner,
247
+ case when settlement_type in ('collection','Claim',"dispute","rectify","rectify_R") and collection_partner = 'fynd' then 'Yes' when settlement_type = 'refund' and refund_partner = 'fynd' then 'Yes' else 'No' end as Comment
248
+ from `fynd-db.finance_recon_tool_asia.09_seller_net_collection_daily`
249
+ where
250
+ (case when settlement_type in ('collection','Claim',"dispute","rectify","rectify_R") and collection_partner = 'fynd' then 'Yes' when settlement_type = 'refund' and refund_partner = 'fynd' then 'Yes' else 'No' end) = 'No'
251
+ ''',
252
+
253
+
254
+ # Query 15
255
+ '15. 09_Net collection collection & refund validation': '''
256
+ select
257
+ A.bag_id,
258
+ B.bag_id,
259
+ A.settlement_type,
260
+ B.settlement_type,
261
+ A.transaction_type,
262
+ A.collection_partner,
263
+ A.refund_partner,
264
+ case when A.settlement_type = 'collection' and A.collection_partner = 'fynd' then 'Yes' when A.settlement_type = 'refund' and A.refund_partner = 'fynd' then 'Yes' else 'No' end as Comment
265
+ from `fynd-db.finance_recon_tool_asia.01_finance_avis_data_final` as A
266
+ left join
267
+ `fynd-db.finance_recon_tool_asia.09_seller_net_collection_daily` as B
268
+ on
269
+ A.bag_id = B.bag_id
270
+ and A.settlement_type = B.settlement_type
271
+ where
272
+ A.settlement_type <> 'NA'
273
+ and A.recon_status not in ("bag_lost","return_bag_lost")
274
+ and (case when A.settlement_type = 'collection' and A.collection_partner = 'fynd' then 'yes' when A.settlement_type = 'refund' and A.refund_partner = 'fynd' then 'yes' else 'No' end) = 'yes'
275
+ and (case when A.transaction_type = 'Sale' and A.collection_partner = 'fynd' then 'Yes' when A.transaction_type = 'Return' and A.refund_partner = 'fynd' then 'Yes' when A.transaction_type = 'Claim' and A.collection_partner = 'fynd' then 'Yes' else 'No' end) = 'Yes'
276
+ and B.bag_id is null
277
+ ''',
278
+
279
+
280
+ # Query 16
281
+ '16. NA settlement validation': '''
282
+ select
283
+ *
284
+ from `fynd-db.finance_recon_tool_asia.09_seller_net_collection_daily`
285
+ where
286
+ -- settlement_type = 'NA'
287
+ (case when settlement_type in ('collection','Claim','rectify','rectify_R') and collection_partner = 'fynd' then 'Yes' when settlement_type = 'refund' and refund_partner = 'fynd' then 'Yes' else 'No'end ) = 'No'
288
+ ''',
289
+
290
+
291
+ # Query 17
292
+ '17. Fynd collection placed bags validation': '''
293
+ select
294
+ A.bag_id,
295
+ B.bag_id,
296
+ A.order_type,
297
+ A.transaction_type,
298
+ case when B.settlement_type = 'collection' then 'Sale' else 'Return' end as transaction_type,
299
+ from `fynd-db.finance_recon_tool_asia.11_seller_fees_daily` as A
300
+ left join
301
+ `fynd-db.finance_recon_tool_asia.09_seller_net_collection_daily` as B
302
+ on
303
+ A.bag_id = B.bag_id
304
+ and A.transaction_type = (case when B.settlement_type = 'collection' then 'Sale' when B.settlement_type = 'refund' then 'Return' else 'NA' end )
305
+ where
306
+ transaction_type <> 'SLA'
307
+ and (case when A.transaction_type = 'Sale' and A.collection_partner = 'fynd' then 'yes' when A.transaction_type = 'Return' and A.refund_partner = 'fynd' then 'yes' else 'no'end) = 'yes'
308
+ and B.bag_id is null
309
+ ''',
310
+
311
+
312
+ # # Query 18
313
+ # '18. PPD seller amount validation': '''
314
+ # select
315
+ # *
316
+ # from
317
+ # (SELECT
318
+ # *
319
+ # FROM
320
+ # `fynd-db.Outstanding.09_Payable_File`
321
+ # where
322
+ # expected_payout_date <= current_date()
323
+ # and order_type = "PPD"
324
+ # and lower(collection_partner) = "seller") as A
325
+ # left join
326
+ # (select
327
+ # bag_id,
328
+ # txn_id,
329
+ # collected_amount
330
+ # from
331
+ # `fynd-db.finance_recon_tool_asia.05_partner_collection`) as B
332
+ # on
333
+ # A.bag_id = B.bag_id
334
+ # where
335
+ # B.bag_id is not null
336
+ # ''',
337
+
338
+
339
+ # Query 19
340
+ '19. Checking sett_id count in payout process table': '''
341
+ select
342
+ sett_id,
343
+ count(sett_id)
344
+ from `fynd-db.finance_recon_tool_asia.payout_process_table`
345
+ group by
346
+ 1
347
+ having
348
+ count(sett_id) <> 1
349
+ ''',
350
+
351
+ # Query 20
352
+ '20. Checking bagwise payout report': '''
353
+ select
354
+ UTR,
355
+ paid_amt,
356
+ dispute,
357
+ round(sum(Net_Payout),2) as payable,
358
+ round(sum(Net_Payout)+dispute-paid_amt) as Diff
359
+ from `fynd-db.finance_recon_tool_asia.Bag_Wise_Payout_Report`
360
+ where
361
+ UTR in (select
362
+ utr_no
363
+ from
364
+ `fynd-db.finance_recon_tool_asia.14_seller_payouts_New`
365
+ where
366
+ sett_date > "2024-04-01" )
367
+ group by
368
+ 1,2,3
369
+ having Diff <> 0
370
+ ''',
371
+
372
+ # Query 21
373
+ '21. Checking claimwise payout report': '''
374
+ select
375
+ SF_UTR,
376
+ total_utr_paid,
377
+ round(sum(claimable_amt),2),
378
+ round(sum(claimable_amt)-total_utr_paid) as Diff
379
+ from `fynd-db.finance_recon_tool_asia.Shipment_wise_Claim_UTR`
380
+ where
381
+ SF_UTR in ("_2414920231016000202198812",
382
+ "_2414920231016000202197711",
383
+ "_AXISCN0279665404",
384
+ "_AXISCN0312196630",
385
+ "_2414920231016000202198811")
386
+ group by
387
+ 1,2
388
+ ''',
389
+
390
+ # # Query 23
391
+ # '23. Checking any settlement id is updated after the payment ': '''
392
+ # select
393
+ # A.sett_id,
394
+ # sum(net_amount)as NA,
395
+ # case when NC is null then 0 else NC end as N,
396
+ # case when SF is null then 0 else SF end as S,
397
+ # case when MD is null then 0 else MD end as M,
398
+ # case when CL is null then 0 else CL end as C,
399
+ # round(sum(net_amount)-(case when NC is null then 0 else NC end)-(case when SF is null then 0 else SF end)-(case when MD is null then 0 else MD end)-(case when CL is null then 0 else CL end)) as diff
400
+ # from
401
+ # `fynd-db.finance_recon_tool_asia.13_seller_disbursement_payouts` as A
402
+ # left join
403
+ # (select
404
+ # sett_id,
405
+ # SUM(seller_net_collection) AS NC
406
+ # from
407
+ # `fynd-db.finance_recon_tool_asia.09_seller_net_collection_daily`
408
+ # GROUP BY
409
+ # 1) as B
410
+ # on
411
+ # A.sett_id = B.sett_id
412
+ # left join
413
+ # (Select
414
+ # sett_id,
415
+ # SUM(total_charges) as SF
416
+ # from
417
+ # `fynd-db.finance_recon_tool_asia.11_seller_fees_daily`
418
+ # GROUP BY
419
+ # 1) as C
420
+ # on
421
+ # A.sett_id = C.sett_id
422
+ # left join
423
+ # (Select
424
+ # sett_id,
425
+ # SUM(dispute_amount) as MD
426
+ # from
427
+ # `fynd-db.finance_recon_tool_asia.17_seller_manual_Dispute`
428
+ # GROUP BY
429
+ # 1) as D
430
+ # on
431
+ # A.sett_id = D.sett_id
432
+ # left join
433
+ # (Select
434
+ # sett_id,
435
+ # SUM(claimable_amt) as CL
436
+ # from
437
+ # `fynd-db.finance_recon_tool_asia.12_seller_claims_daily`
438
+ # GROUP BY
439
+ # 1) as E
440
+ # on
441
+ # A.sett_id = E.sett_id
442
+ # where
443
+ # payout_id in ("2250_OE_COD_19_SD_034_FY24",
444
+ # "2250_OE_COD_21_SD_034_FY24",
445
+ # "0292_FS_COD_AC_SD_034_FY24",
446
+ # "0517_OE_COD_AC_SD_034_FY24",
447
+ # "0042_OE_COD_05_SD_034_FY24",
448
+ # "0034_OM_COD_AC_SD_034_FY24",
449
+ # "0021_OE_COD_AC_SD_034_FY24",
450
+ # "0046_OE_COD_10_SD_034_FY24",
451
+ # "0442_OE_COD_07_SD_034_FY24",
452
+ # "0320_OE_COD_28_SD_034_FY24",
453
+ # "0046_OE_COD_13_SD_034_FY24",
454
+ # "0269_OE_COD_04_SD_034_FY24",
455
+ # "3557_OE_COD_AC_SD_034_FY24",
456
+ # "0025_FS_COD_AC_SD_034_FY24",
457
+ # "3523_FS_COD_AC_SD_034_FY24",
458
+ # "0320_OM_COD_AC_SD_034_FY24",
459
+ # "2467_OE_COD_AC_SD_034_FY24",
460
+ # "0680_UN_COD_MA_SD_034_FY24",
461
+ # "0021_FS_COD_AC_SD_034_FY24",
462
+ # "0442_FS_COD_AC_SD_034_FY24",
463
+ # "0046_FS_COD_AC_SD_034_FY24",
464
+ # "0046_OE_COD_14_SD_034_FY24",
465
+ # "0046_OE_COD_09_SD_034_FY24",
466
+ # "1076_OE_COD_17_SD_034_FY24",
467
+ # "0334_FS_COD_AC_SD_034_FY24",
468
+ # "0046_OE_COD_08_SD_034_FY24",
469
+ # "0334_OE_COD_06_SD_034_FY24",
470
+ # "2250_OE_COD_22_SD_034_FY24",
471
+ # "0002_FS_COD_AC_SD_034_FY24",
472
+ # "2411_OM_COD_AC_SD_034_FY24")
473
+ # group by
474
+ # 1,3,4,5,NC,SF,MD,CL
475
+ # having
476
+ # round(sum(net_amount)-(case when NC is null then 0 else NC end)-(case when SF is null then 0 else SF end)-(case when MD is null then 0 else MD end)) <> 0
477
+ # ''',
478
+
479
+ # Query 22
480
+ '22. Checking any old data inserted into new table': '''
481
+ select
482
+ A.bag_id,
483
+ collection_partner,
484
+ Settlement_type,
485
+ inserted_date,
486
+ B.bag_id,
487
+ B.Transaction_type
488
+ from `fynd-db.finance_recon_tool_asia.01_finance_avis_data_final` as A
489
+ left join
490
+ `fynd-db.finance_dwh.Brand_Settlement_pulse` as B
491
+ on A.bag_id = B.bag_id
492
+ and (case when Settlement_type = 'collection' then 'Sale'when Settlement_type = 'refund' then 'Return' else 'Claim' end) = B.Transaction_type
493
+ where
494
+ Settlement_type <> 'NA'
495
+ and B.bag_id is not null
496
+ group by
497
+ 1,2,3,4,5,6
498
+ ''',
499
+
500
+ # Query 23
501
+ '23. Checking old lost claim check inserted into new table': '''
502
+ select
503
+ *
504
+ from `fynd-db.finance_recon_tool_asia.01_finance_avis_data_final`
505
+ where
506
+ Bag_ID in (select
507
+ Bag_ID
508
+ from `fynd-db.finance_dwh.Brand_Lost_settlement`
509
+ group by
510
+ 1)
511
+ and transaction_type = 'Claim'
512
+ ''',
513
+
514
+
515
+ # Query 24
516
+ '24. Checking duplicate count in bag_wise payout report ': '''
517
+ with bag_count as
518
+ (select
519
+ bag_id,
520
+ transaction_type,
521
+ concat(bag_id,transaction_type) as merged,
522
+ count(concat(bag_id,transaction_type)) as bag_count
523
+ from `fynd-db.finance_recon_tool_asia.Bag_Wise_Payout_Report`
524
+ group by
525
+ 1,2,3)
526
+
527
+ select
528
+ A.bag_id,
529
+ company_id,
530
+ company_name,
531
+ Payment_Date,
532
+ A.transaction_type,
533
+ UTR,
534
+ concat(A.bag_id,A.transaction_type) as merged,
535
+ bag_count,
536
+ seller_net_collection,
537
+ total_charges,
538
+ Net_Payout
539
+ from `fynd-db.finance_recon_tool_asia.Bag_Wise_Payout_Report` as A
540
+ left join
541
+ bag_count as B
542
+ on
543
+ concat(A.bag_id,A.transaction_type) = B.merged
544
+ where
545
+ bag_count <> 1
546
+ group by
547
+ 1,2,3,4,5,6,7,8,9,10,11
548
+
549
+ ''',
550
+
551
+
552
+ # Seller sale validation query
553
+
554
+
555
+
556
+
557
+ # Add more queries as needed
558
+ }
query_seller_sale.py ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ queries = {
2
+ "query_seller_net_data": """
3
+ WITH seller_net_data AS (
4
+ SELECT
5
+ company_id,
6
+ company_name,
7
+ ordering_channel,
8
+ segement_code,
9
+ sales_channel,
10
+ settlement_model,
11
+ settlement_model_code,
12
+ order_type,
13
+ order_date,
14
+ fiscal_year,
15
+ bag_id,
16
+ settlement_type,
17
+ recon_status,
18
+ return_window_date,
19
+ payout_window_date,
20
+ expected_payout_date,
21
+ sett_no,
22
+ sett_id,
23
+ mrp,
24
+ seller_discounts,
25
+ store_discount_amount,
26
+ bca,
27
+ product_gst_perc,
28
+ round(vog,2) as vog,
29
+ tds_on_bca,
30
+ tcs_on_vog,
31
+ seller_fees,
32
+ seller_tender_value,
33
+ round(seller_net_collection,2) as seller_net_collection,
34
+ ROUND(mrp - seller_discounts - store_discount_amount,2) AS bca_cc,
35
+ ROUND(bca - (mrp - seller_discounts - store_discount_amount),2) AS diff_bca_cc,
36
+ ROUND((mrp - seller_discounts - store_discount_amount) * 100 / (100 + ABS(product_gst_perc)), 2) AS vog_cc,
37
+ ROUND(vog - ROUND((mrp - seller_discounts - store_discount_amount) * 100 / (100 + ABS(product_gst_perc)), 2),2) AS diff_vog_cc,
38
+
39
+ -- TDS calculation logic
40
+ CASE
41
+ WHEN segement_code IN ("FY", "UN") AND DATE(order_date) >= '2024-10-01' THEN
42
+ ROUND((mrp - seller_discounts - store_discount_amount), 2) * 0.001
43
+ WHEN segement_code IN ("FY", "UN") AND DATE(order_date) < '2024-10-01' THEN
44
+ ROUND((mrp - seller_discounts - store_discount_amount), 2) * 0.01
45
+ ELSE 0
46
+ END AS tds_cc,
47
+
48
+ -- TCS calculation logic
49
+ CASE
50
+ WHEN segement_code IN ("FY", "UN") AND DATE(order_date) >= '2024-07-10' THEN
51
+ ROUND((mrp - seller_discounts - store_discount_amount) * 100 / (100 + ABS(product_gst_perc)), 2) * 0.005
52
+ WHEN segement_code IN ("FY", "UN") AND DATE(order_date) < '2024-07-10' THEN
53
+ ROUND((mrp - seller_discounts - store_discount_amount) * 100 / (100 + ABS(product_gst_perc)), 2) * 0.01
54
+ ELSE 0
55
+ END AS tcs_cc
56
+ FROM
57
+ `fynd-db.finance_recon_tool_asia.09_seller_net_collection_daily`
58
+ WHERE
59
+ expected_payout_date BETWEEN "{start_date}" AND "{end_date}"
60
+ ),
61
+
62
+ -- Subquery to count occurrences of each bag_id and concatenation of bag_id and settlement_type
63
+ bag_con_count_data AS (
64
+ SELECT
65
+ bag_id,
66
+ settlement_type,
67
+ COUNT(*) AS bagg_count,
68
+ CONCAT(bag_id, settlement_type) AS bag_settlement_concat,
69
+ COUNT(CONCAT(bag_id, settlement_type)) AS bag_settlement_concat_count -- Count of concatenated values
70
+ FROM
71
+ seller_net_data
72
+ GROUP BY
73
+ bag_id, settlement_type
74
+ )
75
+
76
+ -- Final query
77
+ SELECT
78
+ sd.*,
79
+ ROUND((tds_cc - tds_on_bca), 2) AS diff_tds,
80
+ ROUND((tcs_cc - tcs_on_vog), 2) AS diff_tcs,
81
+ ROUND((mrp - seller_discounts - store_discount_amount - seller_tender_value + seller_fees),2) AS seller_sale_cc,
82
+ ROUND(((mrp - seller_discounts - store_discount_amount - seller_tender_value + seller_fees) - tds_cc - tcs_cc),2) AS seller_net_cc,
83
+ ROUND(((mrp - seller_discounts - store_discount_amount - seller_tender_value + seller_fees) - tds_cc - tcs_cc - seller_net_collection), 2) AS net_diff_cc,
84
+ CONCAT(sd.bag_id, ",") AS conccat, -- Concatenated bag_id
85
+ CONCAT(sd.bag_id, sd.settlement_type) AS bag_cc, -- Bag ID with settlement type
86
+ bcc.bagg_count AS bag_count, -- Count of each bag_id and settlement type
87
+ bcc.bag_settlement_concat AS bag_con, -- Concatenated bag_id and settlement_type
88
+ bcc.bag_settlement_concat_count AS bag_con_count, -- Count of concatenated values
89
+ CASE
90
+ WHEN order_type = 'COD' THEN CONCAT(company_id, '_', segement_code, '_', settlement_model_code, '_', order_type, '_V')
91
+ WHEN order_type = 'PPD' THEN CONCAT(company_id, '_', segement_code, '_', settlement_model_code, '_', order_type, '_C')
92
+ END AS ledger_name
93
+ FROM
94
+ seller_net_data sd
95
+ LEFT JOIN
96
+ bag_con_count_data bcc
97
+ ON
98
+ sd.bag_id = bcc.bag_id AND sd.settlement_type = bcc.settlement_type;
99
+ """,
100
+
101
+ "query_brand_accounting_entries": """
102
+ SELECT
103
+ DENSE_RANK() OVER (ORDER BY expected_payout_date,company_id,VOUCHERTYPENAME,sales_channel,expected_payout_date,order_type ASC) entry_code,
104
+ DATE,
105
+ Mode,
106
+ VOUCHERTYPENAME,
107
+ Narration,
108
+ DebitLedger,
109
+ AmountDebitLedger,
110
+ CreditLedger,
111
+ AmountCreditLedger
112
+ FROM (
113
+ WITH
114
+ Truth_table AS (SELECT * FROM `fynd-db.Brand_Accounting_Entries_Asia.Brand_Seller_Sale_FY25_Table`)
115
+ SELECT
116
+ expected_payout_date,
117
+ format_date('%Y%m%d', expected_payout_date) as DATE,
118
+ "Journal" as Mode,
119
+ VOUCHERTYPENAME,
120
+ CONCAT(Narration," for ", sales_channel, " for the period ",expected_payout_date ) AS Narration,
121
+ entry_Type,
122
+ order_type,
123
+ A.segement_code,
124
+ company_id,
125
+ sales_channel,
126
+ CASE WHEN seller_sales_amount > 0 AND B.ordering_channel IN ("FY", "FP", "FS", "UN", "OE","OM") AND entity = "seller" AND mop = "COD" THEN ledger_name WHEN seller_sales_amount > 0 AND B.ordering_channel IN ("FY", "FP", "FS", "UN", "OE","OM") AND entity = "seller" AND mop = "PPD" THEN ledger_name ELSE Credit_Ledger END AS DebitLedger,
127
+ CASE WHEN seller_sales_amount > 0 THEN ROUND(seller_sales_amount*-1) ELSE ROUND(seller_sales_amount) END AS AmountDebitLedger,
128
+ CASE WHEN seller_sales_amount < 0 AND B.ordering_channel IN ("FY", "FP", "FS", "UN", "OE","OM") AND entity = "seller" AND mop = "COD" THEN ledger_name WHEN seller_sales_amount < 0 AND B.ordering_channel IN ("FY", "FP", "FS", "UN", "OE","OM") AND entity = "seller" AND mop = "PPD" THEN ledger_name ELSE Credit_Ledger END AS CreditLedger,
129
+ CASE WHEN seller_sales_amount < 0 THEN ROUND(seller_sales_amount)*-1 ELSE ROUND(seller_sales_amount) END AS AmountCreditLedger
130
+ FROM
131
+ `fynd-db.Brand_Accounting_Entries_Asia.Seller_sale_Logic` AS A
132
+ LEFT JOIN
133
+ Truth_table as B
134
+ ON
135
+ A.segement_code = B.ordering_channel
136
+ AND A.entry_Type = B.Status
137
+ AND A.order_type = B.mop
138
+ WHERE
139
+ order_type = 'COD'
140
+ AND expected_payout_date BETWEEN '{start_date}' AND '{end_date}'
141
+ GROUP BY
142
+ 1,2,3,4,5,6,7,8,9,10,11,12,13,14
143
+ ORDER BY
144
+ expected_payout_date,company_id,VOUCHERTYPENAME,sales_channel,order_type ASC
145
+ )
146
+ ORDER BY entry_code ASC
147
+ """
148
+ }
requirements.txt ADDED
@@ -0,0 +1,243 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ absl-py==2.1.0
2
+ accelerate==0.33.0
3
+ aiofiles==23.2.1
4
+ aiohttp==3.9.5
5
+ aiohttp-retry==2.8.3
6
+ aiosignal==1.3.1
7
+ altair==4.2.2
8
+ annotated-types==0.7.0
9
+ anyio==4.4.0
10
+ APScheduler==3.10.4
11
+ asana==5.0.10
12
+ astunparse==1.6.3
13
+ async-timeout==4.0.3
14
+ attrs==23.2.0
15
+ Automat==24.8.1
16
+ bcrypt==4.2.1
17
+ beautifulsoup4==4.12.3
18
+ blinker==1.8.2
19
+ Brotli==1.1.0
20
+ cachetools==5.3.3
21
+ cairocffi==1.7.1
22
+ CairoSVG==2.7.1
23
+ captcha==0.6.0
24
+ certifi==2024.8.30
25
+ cffi==1.16.0
26
+ chardet==5.2.0
27
+ charset-normalizer==3.3.2
28
+ click==8.1.7
29
+ cloudevents==1.11.0
30
+ constantly==23.10.4
31
+ contourpy==1.2.1
32
+ cryptography==43.0.0
33
+ css==0.1
34
+ cssselect2==0.7.0
35
+ cycler==0.12.1
36
+ datasets==2.20.0
37
+ db-dtypes==1.2.0
38
+ defusedxml==0.7.1
39
+ Deprecated==1.2.14
40
+ deprecation==2.1.0
41
+ dill==0.3.8
42
+ distro==1.9.0
43
+ entrypoints==0.4
44
+ et-xmlfile==1.1.0
45
+ evaluate==0.4.2
46
+ exceptiongroup==1.2.1
47
+ extra-streamlit-components==0.1.71
48
+ fastapi==0.115.4
49
+ ffmpy==0.4.0
50
+ filelock==3.15.4
51
+ Flask==3.0.3
52
+ flatbuffers==24.3.25
53
+ fonttools==4.53.1
54
+ fpdf==1.7.2
55
+ frozenlist==1.4.1
56
+ fsspec==2024.5.0
57
+ functions-framework==3.8.0
58
+ gast==0.6.0
59
+ gitdb==4.0.11
60
+ GitPython==3.1.43
61
+ google-api-core==2.19.0
62
+ google-api-python-client==2.140.0
63
+ google-auth==2.32.0
64
+ google-auth-httplib2==0.2.0
65
+ google-auth-oauthlib==1.2.0
66
+ google-cloud==0.34.0
67
+ google-cloud-bigquery==3.24.0
68
+ google-cloud-bigquery-datatransfer==3.18.0
69
+ google-cloud-bigquery-storage==2.25.0
70
+ google-cloud-core==2.4.1
71
+ google-cloud-storage==2.18.0
72
+ google-crc32c==1.5.0
73
+ google-pasta==0.2.0
74
+ google-resumable-media==2.7.1
75
+ googleapis-common-protos==1.63.1
76
+ gradio==4.44.1
77
+ gradio_client==1.3.0
78
+ grpcio==1.64.1
79
+ grpcio-status==1.62.2
80
+ gspread==6.1.2
81
+ gspread-dataframe==4.0.0
82
+ gunicorn==22.0.0
83
+ h11==0.14.0
84
+ h5py==3.11.0
85
+ html2image==2.0.4.3
86
+ html5lib==1.1
87
+ httpcore==1.0.5
88
+ httplib2==0.22.0
89
+ httpx==0.27.0
90
+ huggingface-hub==0.24.1
91
+ hyperlink==21.0.0
92
+ idna==3.7
93
+ importlib_metadata==8.0.0
94
+ importlib_resources==6.4.0
95
+ incremental==24.7.2
96
+ itsdangerous==2.2.0
97
+ Jinja2==3.1.4
98
+ jsonschema==4.22.0
99
+ jsonschema-specifications==2023.12.1
100
+ keras==3.4.1
101
+ kiwisolver==1.4.5
102
+ libclang==18.1.1
103
+ lxml==5.2.2
104
+ Markdown==3.6
105
+ markdown-it-py==3.0.0
106
+ MarkupSafe==2.1.5
107
+ matplotlib==3.9.1
108
+ mdurl==0.1.2
109
+ ml-dtypes==0.4.0
110
+ mpmath==1.3.0
111
+ multidict==6.0.5
112
+ multiprocess==0.70.16
113
+ namex==0.0.8
114
+ networkx==3.2.1
115
+ ngrok==1.3.0
116
+ numpy==1.26.4
117
+ oauth2client==4.1.3
118
+ oauthlib==3.2.2
119
+ openai==0.28.0
120
+ openpyxl==3.1.4
121
+ opt-einsum==3.3.0
122
+ optree==0.12.1
123
+ orjson==3.10.11
124
+ outcome==1.3.0.post0
125
+ packaging==24.1
126
+ pandas==2.2.2
127
+ pdf2image==1.17.0
128
+ pdfkit==1.0.0
129
+ pdfminer.six==20231228
130
+ pdfplumber==0.11.4
131
+ pikepdf==8.15.1
132
+ pillow==10.3.0
133
+ plotly==5.24.1
134
+ proto-plus==1.24.0
135
+ protobuf==4.25.3
136
+ psutil==6.0.0
137
+ pyarrow==16.1.0
138
+ pyarrow-hotfix==0.6
139
+ pyasn1==0.6.0
140
+ pyasn1_modules==0.4.0
141
+ pycparser==2.22
142
+ pydantic==2.8.2
143
+ pydantic_core==2.20.1
144
+ pydeck==0.9.1
145
+ PyDrive==1.3.1
146
+ PyDrive2==1.20.0
147
+ pydub==0.25.1
148
+ pydyf==0.11.0
149
+ Pygments==2.18.0
150
+ PyJWT==2.8.0
151
+ PyMuPDF==1.24.13
152
+ pyngrok==7.2.0
153
+ pyOpenSSL==24.2.1
154
+ pyparsing==3.1.2
155
+ PyPDF2==3.0.1
156
+ pypdfium2==4.30.0
157
+ pyperclip==1.9.0
158
+ pyphen==0.16.0
159
+ PySocks==1.7.1
160
+ pytesseract==0.3.10
161
+ python-dateutil==2.9.0.post0
162
+ python-decouple==3.8
163
+ python-docx==1.1.2
164
+ python-dotenv==1.0.1
165
+ python-multipart==0.0.17
166
+ pytz==2024.1
167
+ PyYAML==6.0.1
168
+ referencing==0.35.1
169
+ regex==2024.5.15
170
+ reportlab==4.2.2
171
+ requests==2.32.3
172
+ requests-oauthlib==2.0.0
173
+ rich==13.7.1
174
+ rpds-py==0.18.1
175
+ rsa==4.9
176
+ ruff==0.7.2
177
+ safetensors==0.4.3
178
+ schedule==1.2.2
179
+ selenium==4.22.0
180
+ semantic-version==2.10.0
181
+ shellingham==1.5.4
182
+ six==1.16.0
183
+ slack_sdk==3.31.0
184
+ smmap==5.0.1
185
+ sniffio==1.3.1
186
+ sortedcontainers==2.4.0
187
+ soupsieve==2.5
188
+ srv==1.1.0
189
+ st-pages==1.0.1
190
+ st-theme==1.2.3
191
+ starlette==0.41.2
192
+ streamlit==1.37.0
193
+ streamlit-aggrid==1.0.5
194
+ streamlit-authenticator==0.1.5
195
+ streamlit-navigation-bar==3.3.0
196
+ streamlit-option-menu==0.3.13
197
+ streamlit-space==0.1.5
198
+ streamlit-toggle==0.1.3
199
+ streamlit-toggle-switch==1.0.2
200
+ sympy==1.13.1
201
+ tenacity==8.3.0
202
+ tensorboard==2.17.0
203
+ tensorboard-data-server==0.7.2
204
+ tensorflow==2.17.0
205
+ tensorflow-io-gcs-filesystem==0.37.1
206
+ termcolor==2.4.0
207
+ tf_keras==2.17.0
208
+ tinycss2==1.3.0
209
+ tokenizers==0.19.1
210
+ toml==0.10.2
211
+ tomli==2.0.1
212
+ tomlkit==0.12.0
213
+ toolz==0.12.1
214
+ torch==2.4.0
215
+ tornado==6.4.1
216
+ tqdm==4.66.4
217
+ transformers==4.43.3
218
+ trio==0.25.1
219
+ trio-websocket==0.11.1
220
+ twilio==9.2.3
221
+ Twisted==24.7.0
222
+ typer==0.12.5
223
+ typing_extensions==4.12.2
224
+ tzdata==2024.1
225
+ tzlocal==5.2
226
+ uritemplate==4.1.1
227
+ urllib3==2.2.3
228
+ uvicorn==0.32.0
229
+ watchdog==4.0.1
230
+ weasyprint==62.3
231
+ webencodings==0.5.1
232
+ websocket-client==1.8.0
233
+ websockets==12.0
234
+ Werkzeug==3.0.3
235
+ wrapt==1.16.0
236
+ wsproto==1.2.0
237
+ xlrd==2.0.1
238
+ XlsxWriter==3.2.0
239
+ xxhash==3.4.1
240
+ yarl==1.9.4
241
+ zipp==3.19.2
242
+ zope.interface==7.0.3
243
+ zopfli==0.2.3
sample_template (1).xlsx ADDED
Binary file (5.68 kB). View file
 
sample_template (11).xlsx ADDED
Binary file (5.67 kB). View file
 
sample_template.xlsx ADDED
Binary file (5.68 kB). View file
 
slack.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Define your Slack email addresses and webhook URLs
2
+ Slack_email_addresses = {
3
+ 'Rahul Mandowara': 'aaaankma7mqecgi5ckgiutv3ga@gofynd.slack.com',
4
+ 'Abhimanyu':'aaaanm6gie6scddpk5pycnwwma@gofynd.slack.com',
5
+ 'VS': 'aaaaneedladlp3nszpmwwulkay@gofynd.slack.com',
6
+ 'Ninad': 'aaaanfcp5znlb2etchdfewwr3y@gofynd.slack.com',
7
+ 'Priyanshi Nahata': 'aaaandms5io6pfh5qawofrdplm@gofynd.slack.com',
8
+ 'kiran jadhav': 'aaaangzileg6adyfyz6y7siqme@gofynd.slack.com',
9
+ 'Bhavin Parmar': 'aaaannkdegaoe6g3vppkj26ft4@gofynd.slack.com',
10
+ 'RJ': 'aaaanf4e6nhjaryx7ba475qp2e@gofynd.slack.com',
11
+ 'Roshani Mohan': 'aaaanhjh5f2cihhkybe4k7bdre@gofynd.slack.com',
12
+ 'omkarsp': 'aaaanlsvaa7liwu3zgp42artb4@gofynd.slack.com',
13
+ 'Abhilash Sawant': 'aaaanp57acudcxnhlgmoonpsri@gofynd.slack.com',
14
+ 'Hemant Yadav': 'aaaanz2tp3lxatl4uadyc5h24e@gofynd.slack.com',
15
+ 'SandeeP Salunkhe': 'aaaanjukkjprfide3ofd6prno4@gofynd.slack.com',
16
+ 'Sid': 'aaaaneehkkyokdx5ydr5ifktui@gofynd.slack.com',
17
+ 'chetanpatole': 'aaaanptkf3sbppf5jlrlwlzmme@gofynd.slack.com',
18
+ 'Shweta Kanungo': 'aaaannsfn3qehkb4cgfqi7oqbe@gofynd.slack.com',
19
+ 'chandnichaurasia': 'aaaantvq257inlgipy6n3n4oyu@gofynd.slack.com',
20
+ 'Rasika': 'aaaanjz7aqzgmgvbq2j2erk2xi@gofynd.slack.com',
21
+ 'Bhushan Khapare': 'aaaanhompmuol3cupdtcbhyzaa@gofynd.slack.com',
22
+ 'Vaibhavi':'aaaanimf7vltovi7cs5gwknmre@gofynd.slack.com',
23
+ 'daily-alerts-for-unsubscribed-companies': 'daily-alerts-for-unsu-aaaanufptnpzgjtmknapgi45oq@gofynd.slack.com',
24
+ 'finance_team_internal': 'finance_team_internal-aaaabrz6gd5km3hjwxs7saxa4a@gofynd.slack.com',
25
+ 'valyx-fynd-poc': 'valyx-fynd-poc-aaaamwv2kpahjf3krqa752pate@gofynd.slack.com',
26
+ 'valyx_auto_invoices': 'valyx_auto_invoices-aaaanykb7mbnlhtajda4slllia@gofynd.slack.com',
27
+ 'recon-check': 'recon-check-aaaan32uofkccdehnmkymfp5qu@gofynd.slack.com'
28
+ }
29
+
30
+ gmail_addresses = {
31
+ 'Rahul Mandowara': 'rahulmandowara@gofynd.com',
32
+ 'Abhimanyu':'abhimanyumallik@gofynd.com',
33
+ 'VS': 'vikysangoi@gofynd.com',
34
+ 'Ninad': 'ninadmandavkar@gofynd.com',
35
+ 'omkarsp': 'omkarsp@gofynd.com',
36
+ 'Priyanshi Nahata': 'priyanshinahata@gofynd.com',
37
+ 'kiran jadhav': 'kiranjadhav@gofynd.com',
38
+ 'Bhavin Parmar': 'bhavinparmar@gofynd.com',
39
+ 'RJ': 'rasikajadhav@gofynd.com',
40
+ 'Roshani Mohan': 'roshanimohan@gofynd.com',
41
+ 'Abhilash Sawant': 'abhilashsawant@gofynd.com',
42
+ 'Hemant Yadav': 'hemantyadav@gofynd.com',
43
+ 'SandeeP Salunkhe': 'sandeepsalunkhe@gofynd.com',
44
+ 'Sid': 'siddheshmayekar@gofynd.com',
45
+ 'chetanpatole': 'chetanpatole@gofynd.com',
46
+ 'Shweta Kanungo': 'shwetakanungo@gofynd.com',
47
+ 'chandnichaurasia': 'chandnichaurasia@gofynd.com',
48
+ 'Rasika': 'rasikasalunkhe@gofynd.com',
49
+ 'Bhushan Khapare': 'bhushankhapare@gofynd.com',
50
+ 'Vaibhavi': 'vaibhavidambe@gofynd.com',
51
+ 'daily-alerts-for-unsubscribed-companies': 'daily-alerts-for-unsu-aaaanufptnpzgjtmknapgi45oq@gofynd.slack.com',
52
+ 'finance_team_internal': 'finance_team_internal-aaaabrz6gd5km3hjwxs7saxa4a@gofynd.slack.com',
53
+ 'valyx-fynd-poc': 'valyx-fynd-poc-aaaamwv2kpahjf3krqa752pate@gofynd.slack.com',
54
+ 'valyx_auto_invoices': 'valyx_auto_invoices-aaaanykb7mbnlhtajda4slllia@gofynd.slack.com',
55
+ 'recon-check': 'recon-check-aaaan32uofkccdehnmkymfp5qu@gofynd.slack.com'
56
+ }
57
+
58
+ Webhook_urls = {
59
+ 'Rahul Mandowara': 'https://hooks.slack.com/services/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',
60
+ 'Abhimanyu':'https://hooks.slack.com/services/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',
61
+ 'VS': 'https://hooks.slack.com/services/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',
62
+ 'Ninad': 'https://hooks.slack.com/services/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',
63
+ 'kiran jadhav': 'https://hooks.slack.com/services/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',
64
+ 'RJ': 'https://hooks.slack.com/services/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',
65
+ 'Roshani Mohan': 'https://hooks.slack.com/services/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',
66
+ 'omkarsp': 'https://hooks.slack.com/services/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',
67
+ 'Abhilash Sawant': 'https://hooks.slack.com/services/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',
68
+ 'Hemant Yadav': 'https://hooks.slack.com/services/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',
69
+ 'SandeeP Salunkhe': 'https://hooks.slack.com/services/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',
70
+ 'Sid': 'https://hooks.slack.com/services/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',
71
+ 'chetanpatole': 'https://hooks.slack.com/services/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',
72
+ 'Shweta Kanungo': 'https://hooks.slack.com/services/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',
73
+ 'chandnichaurasia': 'https://hooks.slack.com/services/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',
74
+ 'Bhushan Khapare': 'https://hooks.slack.com/services/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',
75
+ 'Vaibhavi': 'https://hooks.slack.com/services/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',
76
+ 'daily-alerts-for-unsubscribed-companies': 'https://hooks.slack.com/services/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',
77
+ 'finance_team_internal': 'https://hooks.slack.com/services/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',
78
+ 'valyx-fynd-poc': 'https://hooks.slack.com/services/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',
79
+ 'valyx_auto_invoices': 'https://hooks.slack.com/services/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',
80
+ 'recon-check': 'https://hooks.slack.com/services/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'
81
+ }
82
+
template.csv ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ company_id,name_of_dedcutor,TAN_of_deductor,Invoice_no,Invoice_date,Invoice_value,Section,TDS_deduction_date,TDS_deposited,TDS_certificate_no
2
+ 1,ABC,AAA111000J,FS-I-A00001-FY25,2024-04-01,100.5,194H,2024-04-10,10.5,29u389y83
template.xlsx ADDED
Binary file (8.87 kB). View file
 
utils.py ADDED
@@ -0,0 +1,337 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import pandas as pd
4
+ from google.cloud import bigquery
5
+ from google.oauth2 import service_account
6
+ import streamlit as st
7
+ import requests
8
+ import smtplib
9
+ from email.mime.multipart import MIMEMultipart
10
+ from email.mime.text import MIMEText
11
+ from email.mime.base import MIMEBase
12
+ from email import encoders
13
+ from queries import queries
14
+ from googleapiclient.discovery import build
15
+ from googleapiclient.http import MediaFileUpload
16
+ from google.auth import exceptions
17
+ from google.auth import exceptions
18
+ from google.auth.transport.requests import Request
19
+ from google.auth.exceptions import DefaultCredentialsError
20
+ from google.auth import credentials
21
+ from google.auth import default
22
+
23
+ from google.auth import exceptions
24
+ from google.auth import default
25
+ from google.auth.transport.requests import Request
26
+
27
+
28
+ # Define your email server details
29
+ EMAIL_HOST = 'smtp.gmail.com'
30
+ EMAIL_PORT = 587
31
+ EMAIL_HOST_USER = 'alerter.response@gmail.com'
32
+ EMAIL_HOST_PASSWORD = 'tmid yqlu eglt sfzv'
33
+
34
+ SLACK_BOT_TOKEN = 'xoxb-2151238541-7506161157329-qYCCaocyGDJwwwtOOWLY2SMR'
35
+
36
+ #Authenticate BigQuery
37
+ def authenticate_bigquery():
38
+ creds = load_gcp_credentials()
39
+ if not creds:
40
+ st.error("Unable to load GCP credentials for BigQuery authentication.")
41
+ return None
42
+ return creds
43
+
44
+
45
+
46
+ #Load GCP credentials
47
+ def load_gcp_credentials():
48
+ try:
49
+ # Retrieve GCP credentials from the environment variable
50
+ gcp_credentials_str = os.getenv('GCP_CREDENTIALS')
51
+ if not gcp_credentials_str:
52
+ raise ValueError("GCP_CREDENTIALS environment variable not defined")
53
+
54
+ # Parse the secret (assuming it's a JSON string)
55
+ gcp_credentials = json.loads(gcp_credentials_str)
56
+
57
+ # Save to a temporary file (Google Cloud uses a JSON file for authentication)
58
+ with open("gcp_credentials.json", "w") as f:
59
+ json.dump(gcp_credentials, f)
60
+
61
+ # Authenticate using Google Cloud SDK
62
+ credentials_from_file = service_account.Credentials.from_service_account_file("gcp_credentials.json")
63
+
64
+ # Return the credentials to be used later
65
+ return credentials_from_file
66
+ except Exception as e:
67
+ print(f"Error retrieving or loading GCP credentials: {str(e)}")
68
+ return None
69
+
70
+ # Upload to BQ
71
+ def upload_to_bigquery(df, table_id):
72
+ try:
73
+ # Load the GCP credentials from Hugging Face secret
74
+ bigquery_creds = load_gcp_credentials()
75
+ if not bigquery_creds:
76
+ st.error("Unable to load GCP credentials.")
77
+ return
78
+
79
+ # Initialize BigQuery client with the loaded credentials
80
+ client = bigquery.Client(credentials=bigquery_creds)
81
+
82
+ # Convert the DataFrame to a list of dictionaries
83
+ records = df.to_dict(orient='records')
84
+
85
+ # Prepare the table schema if needed (optional)
86
+ job_config = bigquery.LoadJobConfig(
87
+ write_disposition="WRITE_APPEND", # Use WRITE_TRUNCATE to overwrite, WRITE_APPEND to append
88
+ )
89
+
90
+ # Load the data to BigQuery
91
+ load_job = client.load_table_from_json(records, table_id, job_config=job_config)
92
+ load_job.result() # Wait for the job to complete
93
+
94
+ st.success("Data submitted")
95
+
96
+ except Exception as e:
97
+ st.error(f"An error occurred while uploading to BigQuery: {e}")
98
+
99
+
100
+
101
+ def preprocess_csv(file_path):
102
+ # Load the CSV file
103
+ df = pd.read_csv(file_path)
104
+
105
+ # Define columns to be converted
106
+ date_columns = ['Order_Date', 'State_Date', 'Entry_Month']
107
+
108
+ if 'bag_id_cn' in df.columns:
109
+ df['bag_id_cn'] = df['bag_id_cn'].replace({'\..*': ''}, regex=True).astype('Int64')
110
+
111
+ # Convert specified columns from DD/MM/YY to 'YYYY-MM-DD 00:00:00 UTC'
112
+ for column in date_columns:
113
+ if column in df.columns:
114
+ df[column] = pd.to_datetime(df[column], format='%d/%m/%y', errors='coerce').dt.strftime('%Y-%m-%d 00:00:00 UTC')
115
+
116
+ # Save the preprocessed CSV
117
+ preprocessed_file_path = 'preprocessed_' + os.path.basename(file_path)
118
+ df.to_csv(preprocessed_file_path, index=False)
119
+
120
+ return preprocessed_file_path
121
+
122
+
123
+
124
+ # Function to read files from local path
125
+ def read_file(path):
126
+ try:
127
+ with open(path, 'rb') as file:
128
+ return file.read()
129
+ except Exception as e:
130
+ st.error(f"Failed to read file from {path}: {str(e)}")
131
+ return None
132
+
133
+
134
+
135
+ # Function to get file content type based on file extension
136
+ def get_content_type(file_path):
137
+ if file_path.lower().endswith('.pdf'):
138
+ return 'application/pdf'
139
+ elif file_path.lower().endswith('.csv'):
140
+ return 'text/csv'
141
+ elif file_path.lower().endswith('.xlsx'):
142
+ return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
143
+ else:
144
+ return 'application/octet-stream'
145
+
146
+
147
+
148
+ # Encode the image to Base64
149
+ def get_base64_image(image_path):
150
+ with open(image_path, "rb") as image_file:
151
+ return base64.b64encode(image_file.read()).decode()
152
+
153
+
154
+
155
+ def send_message_via_email(message, email_address, files, subject=None, body=None):
156
+ try:
157
+ # Set up the server
158
+ server = smtplib.SMTP(EMAIL_HOST, EMAIL_PORT)
159
+ server.starttls()
160
+ server.login(EMAIL_HOST_USER, EMAIL_HOST_PASSWORD)
161
+
162
+ # Create the email
163
+ msg = MIMEMultipart()
164
+ msg['From'] = EMAIL_HOST_USER
165
+ msg['To'] = email_address
166
+ msg['Subject'] = subject if subject else "🚨 Alerter"
167
+
168
+ # Attach the message body
169
+ msg.attach(MIMEText(body if body else message, 'plain'))
170
+
171
+ # Attach each file if provided
172
+ if files:
173
+ for uploaded_file in files:
174
+ part = MIMEBase('application', 'octet-stream')
175
+ part.set_payload(uploaded_file.read())
176
+ encoders.encode_base64(part)
177
+ part.add_header('Content-Disposition', f'attachment; filename={uploaded_file.name}')
178
+ msg.attach(part)
179
+
180
+ # Send the email
181
+ server.sendmail(EMAIL_HOST_USER, email_address, msg.as_string())
182
+ server.quit()
183
+ return True, "Message sent successfully"
184
+ except Exception as e:
185
+ return False, str(e)
186
+
187
+ def send_message_via_webhook(message, webhook_url):
188
+ try:
189
+ payload = {"text": message}
190
+ response = requests.post(webhook_url, json=payload)
191
+ if response.status_code == 200:
192
+ return True, "Message sent successfully"
193
+ else:
194
+ return False, f"Error {response.status_code}: {response.text}"
195
+ except Exception as e:
196
+ return False, str(e)
197
+
198
+
199
+
200
+ def send_file_to_slack(file, webhook_url):
201
+ files = {
202
+ 'file': (file.name, file, 'application/octet-stream') # Send as binary
203
+ }
204
+ response = requests.post(
205
+ webhook_url,
206
+ files=files,
207
+ headers={"Content-Type": "multipart/form-data"}
208
+ )
209
+ return response
210
+
211
+
212
+ def send_file_to_slack_up(file, webhook_url, channel_id):
213
+ # Slack API URL for file upload
214
+ slack_api_url = 'https://slack.com/api/files.upload'
215
+
216
+ # Prepare headers for the API call
217
+ headers = {
218
+ 'Authorization': 'Bearer ' + 'SLACK_BOT_TOKEN', # Replace with your actual Slack bot token
219
+ }
220
+
221
+ # Prepare the payload and file in binary format
222
+ files = {
223
+ 'file': (file.name, file, 'application/octet-stream'), # Send the file in its original binary format
224
+ 'channels': channel_id, # Specify the Slack channel ID where the file should be uploaded
225
+ }
226
+
227
+ # Make the POST request to upload the file to Slack
228
+ response = requests.post(slack_api_url, headers=headers, files=files)
229
+
230
+ return response
231
+
232
+
233
+
234
+ def check_duplicates(client):
235
+ """Check for duplicates using BigQuery with the provided credentials file."""
236
+ results = {}
237
+ bigquery_creds = authenticate_bigquery()
238
+ client = bigquery.Client(credentials=bigquery_creds)
239
+
240
+ for i, (query_name, query) in enumerate(queries.items()):
241
+
242
+ query_job = client.query(query)
243
+ df = query_job.result().to_dataframe()
244
+ # For debugging, write the DataFrame to the Streamlit app
245
+ st.write(f"{query_name}:", df)
246
+
247
+ button_styles = """
248
+ <style>
249
+ div.stButton > button {
250
+ color: #ffffff; /* Text color */
251
+ font-size: 30px;
252
+ background-image: linear-gradient(to right, #800000, #ff0000); /* Maroon to light red gradient */
253
+ border: none;
254
+ padding: 10px 20px;
255
+ cursor: pointer;
256
+ border-radius: 15px;
257
+ display: inline-block;
258
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 8px 15px rgba(0, 0, 0, 0.1); /* Box shadow */
259
+ transition: all 0.3s ease; /* Smooth transition on hover */
260
+ }
261
+ div.stButton > button:hover {
262
+ background-color: #00ff00; /* Hover background color */
263
+ color: #ff0000; /* Hover text color */
264
+ box-shadow: 0 6px 10px rgba(0, 0, 0, 0.2), 0 12px 20px rgba(0, 0, 0, 0.2); /* Box shadow on hover */
265
+ }
266
+ </style>
267
+ """
268
+ st.markdown(button_styles, unsafe_allow_html=True)
269
+ if st.button(f"Copy Query", key=f"copy_query_{i}"):
270
+ pyperclip.copy(query)
271
+ st.success('Query copied to clipboard!')
272
+
273
+ if not df.empty:
274
+ duplicate_count = len(df)
275
+ results[query_name] = duplicate_count
276
+
277
+ return results
278
+
279
+
280
+
281
+ def upload_to_drive(file_path, folder_id):
282
+ try:
283
+ # Authenticate with Google Drive using Hugging Face secrets
284
+ creds = authenticate_google_drive()
285
+ if not creds:
286
+ return
287
+
288
+ # Build the Google Drive service
289
+ service = build('drive', 'v3', credentials=creds)
290
+
291
+ # Define the file metadata
292
+ file_metadata = {'name': os.path.basename(file_path), 'parents': [folder_id]}
293
+ # Determine MIME type based on file extension
294
+ mime_type = 'application/vnd.ms-excel' if file_path.endswith('.xlsx') else 'text/csv'
295
+ media = MediaFileUpload(file_path, mimetype=mime_type)
296
+
297
+ # Upload the file to Google Drive
298
+ file = service.files().create(body=file_metadata, media_body=media, fields='id').execute()
299
+
300
+ st.write("")
301
+ except Exception as e:
302
+ st.error(f"An error occurred: {e}")
303
+ st.error("Ensure the folder ID is correct and the service account has permission to access the folder.")
304
+
305
+
306
+
307
+ def authenticate_google_drive():
308
+ creds = load_gcp_credentials()
309
+ if not creds:
310
+ st.error("Unable to load GCP credentials for Google Drive authentication.")
311
+ return None
312
+ return creds
313
+
314
+
315
+ def get_oauth_token():
316
+ try:
317
+ # Define the required scopes for Dataform
318
+ required_scopes = [
319
+ "https://www.googleapis.com/auth/cloud-platform", # General GCP access
320
+ "https://www.googleapis.com/auth/bigquery", # BigQuery access
321
+ "https://www.googleapis.com/auth/dataform"
322
+ ]
323
+
324
+ # Load the credentials with the specified scopes
325
+ creds, _ = default(scopes=required_scopes)
326
+
327
+ if creds is None:
328
+ raise exceptions.DefaultCredentialsError("No valid credentials found.")
329
+
330
+ # Refresh the credentials to get the latest access token
331
+ creds.refresh(Request())
332
+
333
+ return creds.token
334
+
335
+ except exceptions.GoogleAuthError as e:
336
+ print(f"Authentication error: {e}")
337
+ return None