sars 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
sars-0.1.3/PKG-INFO ADDED
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.3
2
+ Name: sars
3
+ Version: 0.1.3
4
+ Summary: Collect information from Zoho CRM to populate the SARS TCR01 form
5
+ Author: AMI Trading
6
+ Author-email: support@amitrading.co.za
7
+ Requires-Python: >=3.12.2
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.13
10
+ Requires-Dist: selenium (>=4.29.0,<5.0.0)
11
+ Requires-Dist: zohocrmsdk7-0 (>=5.0.0,<6.0.0)
12
+ Description-Content-Type: text/markdown
13
+
14
+ # sars_tcr01
15
+ Python script to collect data from Zoho CRM TCR01 module and automatically update the SARS SOQS TCR01 form along with the operators manual support
16
+
sars-0.1.3/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # sars_tcr01
2
+ Python script to collect data from Zoho CRM TCR01 module and automatically update the SARS SOQS TCR01 form along with the operators manual support
@@ -0,0 +1,21 @@
1
+ [project]
2
+ name = "sars"
3
+ version = "0.1.3"
4
+ description = "Collect information from Zoho CRM to populate the SARS TCR01 form"
5
+ authors = [
6
+ { name = "AMI Trading", email = "support@amitrading.co.za" }
7
+ ]
8
+ readme = "README.md"
9
+ requires-python = ">=3.12.2"
10
+ dependencies = [
11
+ "selenium>=4.29.0,<5.0.0",
12
+ "zohocrmsdk7-0>=5.0.0,<6.0.0"
13
+ ]
14
+ package-mode = false
15
+
16
+ [project.scripts]
17
+ appl = "sars.main:main"
18
+
19
+ [build-system]
20
+ requires = ["poetry-core>=2.0.0,<3.0.0"]
21
+ build-backend = "poetry.core.masonry.api"
File without changes
@@ -0,0 +1,366 @@
1
+ import os
2
+ from pathlib import Path
3
+ from selenium import webdriver
4
+ from selenium.webdriver.common.by import By
5
+ from selenium.webdriver.support.ui import Select
6
+ from selenium.webdriver.common.action_chains import ActionChains
7
+ from selenium.webdriver.common.keys import Keys
8
+ from selenium.webdriver.chrome.service import Service
9
+ from selenium.webdriver.chrome.options import Options
10
+ from selenium.webdriver.support.ui import WebDriverWait
11
+ from selenium.webdriver.support import expected_conditions as EC
12
+ import time
13
+ from zohocrmsdk.src.com.zoho.api.authenticator import OAuthToken
14
+ from zohocrmsdk.src.com.zoho.api.authenticator.store import FileStore
15
+ from zohocrmsdk.src.com.zoho.crm.api.sdk_config import SDKConfig
16
+
17
+
18
+ from zohocrmsdk.src.com.zoho.crm.api import Initializer, ParameterMap, HeaderMap
19
+ from zohocrmsdk.src.com.zoho.crm.api.attachments import Attachment
20
+ from zohocrmsdk.src.com.zoho.crm.api.dc import USDataCenter
21
+ from zohocrmsdk.src.com.zoho.crm.api.layouts import MinifiedLayout
22
+ from zohocrmsdk.src.com.zoho.crm.api.record import (
23
+ RecordOperations,
24
+ ResponseWrapper,
25
+ FileDetails,
26
+ Reminder,
27
+ Participants,
28
+ ImageUpload,
29
+ PricingDetails,
30
+ Record,
31
+ LineTax,
32
+ Comment,
33
+ RemindAt,
34
+ RecurringActivity,
35
+ Consent,
36
+ FileBodyWrapper,
37
+ APIException,
38
+ GetRecordParam,
39
+ GetRecordHeader,
40
+ )
41
+ from zohocrmsdk.src.com.zoho.crm.api.tags import Tag
42
+ from zohocrmsdk.src.com.zoho.crm.api.taxes import Tax
43
+ from zohocrmsdk.src.com.zoho.crm.api.users import MinifiedUser
44
+ from zohocrmsdk.src.com.zoho.crm.api.util import Choice
45
+
46
+ #Temp
47
+ record_id = int(input("Enter your templates record ID: "))
48
+
49
+
50
+ class GetRecord:
51
+ @staticmethod
52
+ def initialize(zoho_init_details):
53
+ init = {
54
+ "environment": USDataCenter.PRODUCTION(),
55
+ "client_id": zoho_init_details["client_id"],
56
+ "client_secret": zoho_init_details["client_secret"],
57
+ "refresh_token": zoho_init_details["refresh_token"],
58
+ "find_user": False,
59
+ "file_path": zoho_init_details["file_path"],
60
+ "resource_path": zoho_init_details["resource_path"],
61
+ }
62
+ token = OAuthToken(
63
+ client_id=init["client_id"],
64
+ client_secret=init["client_secret"],
65
+ refresh_token=zoho_init_details["refresh_token"],
66
+ find_user=False,
67
+ )
68
+ config = SDKConfig(
69
+ auto_refresh_fields=True,
70
+ pick_list_validation=False,
71
+ connect_timeout=None,
72
+ read_timeout=None,
73
+ )
74
+ Initializer.initialize(
75
+ init["environment"],
76
+ token,
77
+ store=FileStore(file_path=init.get("file_path")),
78
+ resource_path=zoho_init.get("resource_path"),
79
+ )
80
+
81
+ @staticmethod
82
+ def get_record(module_api_name, record_id):
83
+
84
+ record_operations = RecordOperations(module_api_name)
85
+ param_instance = ParameterMap()
86
+ header_instance = HeaderMap()
87
+ response = record_operations.get_record(
88
+ record_id, param_instance, header_instance
89
+ )
90
+ if response is not None:
91
+ print("Status Code: " + str(response.get_status_code()))
92
+ if response.get_status_code() in [204, 304]:
93
+ print(
94
+ "No Content"
95
+ if response.get_status_code() == 204
96
+ else "Not Modified"
97
+ )
98
+ return
99
+ response_object = response.get_object()
100
+ if response_object is not None:
101
+ if isinstance(response_object, ResponseWrapper):
102
+ record_list = response_object.get_data()
103
+ for record in record_list:
104
+ print("Record ID: " + str(record.get_id()))
105
+ return record
106
+
107
+
108
+ elif isinstance(response_object, APIException):
109
+ print("Status: " + response_object.get_status().get_value())
110
+ print("Code: " + response_object.get_code().get_value())
111
+ print("Details")
112
+ details = response_object.get_details()
113
+ for key, value in details.items():
114
+ print(key + " : " + str(value))
115
+ print("Message: " + response_object.get_message().get_value())
116
+
117
+
118
+
119
+
120
+ home_dir = os.path.expanduser("~")
121
+ zoho_environment = os.environ.get("ZOHO_ENV")
122
+ if zoho_environment is None:
123
+ zoho_environment = os.environ.get("ZOHO_CRM_ENV")
124
+ zoho_cvid = {}
125
+
126
+ if zoho_environment is not None and zoho_environment.lower() == "dev":
127
+ zoho_cvid["ZOHO_DEALS"] = "6097624000000507808"
128
+ zoho_cvid["ZOHO_CONTACTS"] = "6097624000000507807"
129
+ zoho_refresh_token = os.environ["ZOHO_REFRESH_TOKEN_DEV"]
130
+ else:
131
+ zoho_cvid["ZOHO_DEALS"] = "4610371000065442049"
132
+ zoho_cvid["ZOHO_CONTACTS"] = "4610371000000319203"
133
+ zoho_refresh_token = os.environ["ZOHO_REFRESH_TOKEN"]
134
+
135
+
136
+ zoho_file_path = Path.home() / ".ssh" / "zoho_tcr_access_token.txt"
137
+ zoho_file_path.parent.mkdir(parents=True, exist_ok=True)
138
+ if not zoho_file_path.exists():
139
+ zoho_file_path.touch()
140
+
141
+ zoho_resource = Path.home() / ".zoho"
142
+ zoho_resource.parent.mkdir(parents=True, exist_ok=True)
143
+ zoho_resource.mkdir(parents=True, exist_ok=True)
144
+
145
+ print(zoho_file_path, zoho_resource )
146
+
147
+ zoho_init = {
148
+ "client_id": os.environ["ZOHO_CLIENT_ID"],
149
+ "client_secret": os.environ["ZOHO_CLIENT_SECRET"],
150
+ "refresh_token": zoho_refresh_token,
151
+ "file_path": str(zoho_file_path) ,
152
+ "resource_path": str(zoho_resource) + '/',
153
+ "cvid": zoho_cvid,
154
+ }
155
+
156
+ module_api_name = "TCRs"
157
+ # record_id = 4610371000081837252
158
+ GetRecord.initialize(zoho_init_details=zoho_init)
159
+ record = GetRecord.get_record(module_api_name, record_id)
160
+
161
+ # exit()
162
+ # Initialize WebDriver
163
+ driver = webdriver.Chrome()
164
+ timeout = 5
165
+ driver.implicitly_wait(timeout)
166
+ source_type = ""
167
+
168
+
169
+
170
+ def fill_input_field(field_id, value, fill = False):
171
+ field = driver.find_element(By.ID, field_id)
172
+ if fill == True and value == None:
173
+ field.send_keys("0")
174
+ elif value == None:
175
+ pass
176
+ else:
177
+ field.send_keys(value)
178
+ time.sleep(0.25)
179
+
180
+
181
+ def fill_dropdown_field(field_name, value):
182
+ tcs_type_dropdown = Select(driver.find_element(By.NAME, field_name))
183
+ tcs_type_dropdown.select_by_visible_text("Value")
184
+ time.sleep(1)
185
+
186
+
187
+ def click_radio_button(radio_id):
188
+ # radio_input = driver.find_element(By.CSS_SELECTOR, f"input#mat-radio-{radio_id}-input")
189
+ # driver.execute_script("arguments[0].click();", radio_input)
190
+ # time.sleep(1) # Pause after clicking the radio button
191
+ pass
192
+
193
+ try:
194
+ # Open the SARS TCR01 form
195
+ driver.get("https://tools.sars.gov.za/sarsonlinequery/tcr01")
196
+
197
+ # Select "Approval International Transfer" from the "TCS Type" dropdown
198
+ tcs_type_dropdown = Select(driver.find_element(By.ID, "tcrType"))
199
+ tcs_type_dropdown.select_by_visible_text("Approval International Transfer")
200
+ time.sleep(1)
201
+
202
+ # Fill out required fields
203
+ fill_input_field("generate_tcrIdNo", record.get_key_value("ID_Number"))
204
+ fill_input_field("generate_tcrTaxRefNo", record.get_key_value("Tax_Number"))
205
+
206
+ # Click Submit
207
+ driver.find_element(By.ID, "GenerateForm").click()
208
+ time.sleep(3)
209
+
210
+ print("Form submitted successfully!")
211
+
212
+ input("Complete the CAPTCHA and press Enter to continue...")
213
+
214
+ # Select Authorised Representative
215
+
216
+ authorised_representative_label = driver.find_element(By.XPATH, "//label[@for='mat-radio-10002-input']")
217
+ authorised_representative_label.click()
218
+
219
+ driver.execute_script("document.getElementById('mat-radio-10025-input').click();")
220
+ time.sleep(1)
221
+
222
+ # Fill in Other Fields
223
+ fill_input_field("mat-input-73", "FSP 53682") # Other Reason
224
+ fill_input_field("mat-input-74", "Delport") # Surname
225
+ fill_input_field("mat-input-75", "Anton David") # First Names
226
+ fill_input_field("mat-input-76", "AD") # Initials
227
+ fill_input_field("mat-input-77", "7703105155081") # ID Number
228
+ fill_input_field("mat-input-82", "0795074441") # Cell Number
229
+ fill_input_field("mat-input-84", "support@amitrading.co.za") # Email
230
+
231
+ # Additional Fields
232
+ # fill_input_field("mat-input-10", "2006") # Date Year
233
+ # fill_input_field("mat-input-11", "06") # Date Month
234
+ # fill_input_field("mat-input-12", "20") # Date Day
235
+ # fill_input_field("mat-input-8", "0") # Home Tel No
236
+ # fill_input_field("mat-input-9", "1") # Business Tel No
237
+
238
+ # Open nect oage
239
+ element = WebDriverWait(driver, timeout).until(
240
+ EC.element_to_be_clickable((By.CSS_SELECTOR, "sars-international-transfer-details gov-panel-description"))
241
+ )
242
+ element.click()
243
+
244
+ # SA Tax Resident
245
+ click_radio_button("mat-radio-10008")
246
+ # fill_input_field("mat-input-14", "ZAF") # Where will you be a tax resident
247
+
248
+ # International Transfer Details
249
+ fill_input_field("mat-input-18", record.get_key_value("Pin_Value")) # Total value
250
+
251
+ # Family Unit Question
252
+ click_radio_button("mat-radio-10011") # Yes
253
+ # click_radio_button("mat-radio-10012") # No
254
+
255
+ # Needs logic to work properly hidden for now
256
+ # Source Type
257
+ # fill_dropdown_field("mat-input-19", source_type.upper()) # Source Type
258
+ # fill_input_field("mat-input-20", "50000") # Proportional Value
259
+ # source_type = source_type.lower()
260
+
261
+
262
+ if source_type == "Cash/Savings":
263
+ pass
264
+ elif source_type == "Distribution from Trust as a beneficiary":
265
+ pass
266
+ elif source_type == "Donation":
267
+ pass
268
+ elif source_type == "Dividents distribution from a Company":
269
+ pass
270
+ elif source_type == "Inheritance":
271
+ pass
272
+ elif source_type == "Loan":
273
+ pass
274
+ elif source_type == "Sale of Property":
275
+ pass
276
+ elif source_type == "Sale of shares and other secutities":
277
+ pass
278
+ elif source_type == "Sale of Crypto Assets":
279
+ pass
280
+ elif source_type == "Transfer of Listed Securities":
281
+ pass
282
+ elif source_type == "Other":
283
+ pass
284
+ else:
285
+ pass
286
+
287
+
288
+ # # Trust Details
289
+ # fill_input_field("mat-input-120", "Example Trust") # Registered Name of Trust
290
+ # fill_input_field("mat-input-121", "123456") # Trust No
291
+ # fill_input_field("mat-input-122", "789101") # Income Tax Ref No
292
+ # fill_input_field("mat-input-123", "200000") # Value for Trust
293
+ # click_radio_button("mat-radio-10043") # Foreign Trust
294
+
295
+ assets_liabilities = WebDriverWait(driver, timeout).until(
296
+ EC.element_to_be_clickable((By.XPATH, '//*[@id="mat-expansion-panel-header-5"]/span[1]/gov-panel-description'))
297
+ )
298
+ assets_liabilities.click()
299
+ time.sleep(1)
300
+
301
+ south_african_assets = WebDriverWait(driver, timeout).until(
302
+ EC.element_to_be_clickable((By.XPATH, '//*[@id="mat-expansion-panel-header-6"]/span[1]/gov-panel-title'))
303
+ )
304
+ south_african_assets.click()
305
+ time.sleep(1)
306
+
307
+
308
+
309
+ # South African Assets
310
+ fill_input_field("mat-input-22", record.get_key_value("Fixed_Properties"), True) # Fixed Property
311
+ fill_input_field("mat-input-23", record.get_key_value("Shares_in_Private_Company"), True) # Private Company Shares
312
+ fill_input_field("mat-input-24", record.get_key_value("Loan_Account"), True) # Loan Accounts
313
+ fill_input_field("mat-input-25", record.get_key_value("Financial_Instruments_no_crypto"), True) # Listed Financial Instruments
314
+ fill_input_field("mat-input-26", record.get_key_value("Financial_Instruments_Crypto"), True) # Crypto Assets
315
+ fill_input_field("mat-input-27", record.get_key_value("Capital_of_Business"), True) # Business Capital
316
+ fill_input_field("mat-input-28", record.get_key_value("Equipment"), True) # Equipment, Machinery, Implements
317
+ fill_input_field("mat-input-29", record.get_key_value("Motor_Vehicles"), True) # Motor Vehicles, Caravans, Boats
318
+ fill_input_field("mat-input-30", record.get_key_value("Debtors"), True) # Debtors
319
+ fill_input_field("mat-input-31", record.get_key_value("Stock"), True) # Stock
320
+ fill_input_field("mat-input-32", record.get_key_value("Livestock"), True) # Livestock - elected value(s)
321
+ fill_input_field("mat-input-33", record.get_key_value("Cash_on_Hand"), True) # Cash on Hand, in Bank and Other Similar Institutions
322
+ fill_input_field("mat-input-34", record.get_key_value("Personal_Effects"), True) # Personal Effects (jewelry, paintings, furniture, etc.)
323
+ fill_input_field("mat-input-35", record.get_key_value("Other_Assets"), True) # Other Assets
324
+
325
+ # South African Liabilities
326
+ fill_input_field("mat-input-37", record.get_key_value("Mortgage_Bonds"), True) # Mortgage Bonds
327
+ fill_input_field("mat-input-38", record.get_key_value("Loan_Accounts"), True) # Loan Accounts
328
+ fill_input_field("mat-input-39", record.get_key_value("Creditors"), True) # Creditors
329
+ fill_input_field("mat-input-40", record.get_key_value("Bank_Overdraft"), True) # Bank Overdraft
330
+ fill_input_field("mat-input-41", record.get_key_value("Other_liabilities"), True) # Other Liabilities)
331
+
332
+ foreign_assets = WebDriverWait(driver, timeout).until(
333
+ EC.element_to_be_clickable((By.XPATH, '//*[@id="mat-expansion-panel-header-9"]/span[1]/gov-panel-title'))
334
+ )
335
+ foreign_assets.click()
336
+
337
+ #foreign assets
338
+ fill_input_field("mat-input-43", record.get_key_value("Fixed_Properties_Forgeign"), True) # Foreign Fixed Properties
339
+ fill_input_field("mat-input-44", record.get_key_value("Shares_in_Private_Company_Forgeign"), True) # Shares in Private Company or Member’s Interest
340
+ fill_input_field("mat-input-45", record.get_key_value("Loan_Account_Forgeign"), True) # Foreign Loan Accounts
341
+ fill_input_field("mat-input-46", record.get_key_value("FInancial_Instruments_no_crypto_Forgeign"), True) # Financial Instruments Listed (excluding crypto)
342
+ fill_input_field("mat-input-47", record.get_key_value("Financial_Instruments_Crypto_Forgeign"), True) # Crypto Assets
343
+ fill_input_field("mat-input-48", record.get_key_value("Capital_of_Buisness_Forgeign"), True) # Net Capital of Business, Trade, Profession or Farming
344
+ fill_input_field("mat-input-49", record.get_key_value("Equipment_Forgeign"), True) # Foreign Equipment, Machinery, Implements
345
+ fill_input_field("mat-input-50", record.get_key_value("Motor_Vehicles_Forgeign"), True) # Foreign Motor Vehicles, Caravans, Boats
346
+ fill_input_field("mat-input-51", record.get_key_value("Debtors_Forgeign"), True) # Foreign Debtors
347
+ fill_input_field("mat-input-52", record.get_key_value("Stock_Forgeign"), True) # Foreign Stock
348
+ fill_input_field("mat-input-53", record.get_key_value("Livestock_Forgeign"), True) # Foreign Livestock - elected value(s)
349
+ fill_input_field("mat-input-54", record.get_key_value("Cash_on_Hand_Forgeign"), True) # Foreign Cash on Hand, in Bank
350
+ fill_input_field("mat-input-55", record.get_key_value("Personal_Effects_Forgeign"), True) # Foreign Personal Effects
351
+ fill_input_field("mat-input-56", record.get_key_value("Other_Assets_Forgeign"), True) # Foreign Other Assets
352
+
353
+
354
+ # Foreign Liabilities
355
+ fill_input_field("mat-input-58", record.get_key_value("Mortgage_Bonds_Forgeign"), True) # Foreign Mortgage Bonds
356
+ fill_input_field("mat-input-59", record.get_key_value("Loan_Accounts_Forgeign"), True) # Foreign Loan Accounts
357
+ fill_input_field("mat-input-60", record.get_key_value("Creditors_Forgeign"), True) # Foreign Creditors
358
+ fill_input_field("mat-input-61", record.get_key_value("Bank_Overdaft_Forgeign"), True) # Foreign Bank Overdraft
359
+ fill_input_field("mat-input-62", record.get_key_value("Other_Liabilities_Forgeign"), True) # Foreign Other Liabilities
360
+
361
+ input("Complete rest manually and press Enter to finish...")
362
+ finally:
363
+ driver.quit()
364
+
365
+ def main():
366
+ pass