ms-salesforce-api 2.24.0.dev5__tar.gz → 3.0.0__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.
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/PKG-INFO +2 -2
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/account/dto/AccountDTO.py +3 -2
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity/__init__.py +1 -2
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity/dto/OpportunityDTO.py +17 -7
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity/export_data/Bigquery.py +2 -2
- ms_salesforce_api-3.0.0/ms_salesforce_api/salesforce/api/project/__init__.py +101 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/project/__tests__/test_Project.py +142 -144
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/project/dto/OpportunityDTO.py +3 -1
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/project/dto/ProjectLineItemDTO.py +15 -1
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/pyproject.toml +1 -1
- ms_salesforce_api-2.24.0.dev5/ms_salesforce_api/salesforce/api/project/__init__.py +0 -109
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/LICENSE +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/README.md +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/Auth.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/JWTGenerator.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/SalesforceQueryExecutor.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/__tests__/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/__tests__/test_Auth.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/__tests__/test_JWTGenerator.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/__tests__/test_SalesforceRequester.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/account/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/account/constants.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/account/dto/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/account/export_data/Bigquery.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/account/export_data/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/contact/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/contact/constants.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/contact/dto/ContactDTO.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/contact/dto/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/contact/export_data/Bigquery.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/contact/export_data/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/lead/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/lead/constants.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/lead/dto/LeadDTO.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/lead/dto/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/lead/export_data/Bigquery.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/lead/export_data/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity/constants.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity/dto/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity/export_data/CloudSQL.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity/export_data/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity/export_data/__tests__/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity/export_data/__tests__/test_CloudSQL.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity/helpers.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity_contact_role/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity_contact_role/constants.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity_contact_role/dto/OpportunityContactDTO.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity_contact_role/dto/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity_contact_role/export_data/Bigquery.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity_contact_role/export_data/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity_history/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity_history/constants.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity_history/dto/OpportunityDTO.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity_history/dto/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity_history/export_data/Bigquery.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/opportunity_history/export_data/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/product/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/product/__tests__/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/product/__tests__/test_Product.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/product/constants.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/product/dto/ProductDTO.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/product/dto/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/product/export_data/Bigquery.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/product/export_data/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/profit_center/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/profit_center/__tests__/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/profit_center/__tests__/test_ProfitCenter.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/profit_center/constants.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/profit_center/dto/ProfitCenterDTO.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/profit_center/dto/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/profit_center/export_data/Bigquery.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/profit_center/export_data/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/project/__tests__/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/project/constants.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/project/dto/BillingLineDTO.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/project/dto/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/project/export_data/Bigquery.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/project/export_data/CloudSQL.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/project/export_data/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/project/export_data/__tests__/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/api/project/export_data/__tests__/test_CloudSQL.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/helpers/__init__.py +0 -0
- {ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/helpers/string.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: ms-salesforce-api
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0
|
|
4
4
|
Summary: Python library used to extract data from Salesforce API and migrate it to Bigquery and Postgres.
|
|
5
5
|
Author: Making Science
|
|
6
6
|
Requires-Python: >=3.8.1,<4.0.0
|
|
@@ -327,9 +327,10 @@ class AccountDTO(object):
|
|
|
327
327
|
owner_email=normalize_value(_get_owner_email()),
|
|
328
328
|
type=normalize_value(record["Type"]),
|
|
329
329
|
industry=normalize_value(record["Industry"]),
|
|
330
|
-
|
|
331
330
|
risk_assessment=normalize_value(record["Risk_Assessment__c"]),
|
|
332
|
-
risk_assessment_date=normalize_value(
|
|
331
|
+
risk_assessment_date=normalize_value(
|
|
332
|
+
record["Risk_Assessment_Date__c"]
|
|
333
|
+
),
|
|
333
334
|
)
|
|
334
335
|
|
|
335
336
|
def to_dict(self):
|
|
@@ -37,8 +37,7 @@ class Opportunity(SalesforceQueryExecutor):
|
|
|
37
37
|
return []
|
|
38
38
|
|
|
39
39
|
opportunities = [
|
|
40
|
-
OpportunityDTO.from_salesforce_record(record)
|
|
41
|
-
for record in data
|
|
40
|
+
OpportunityDTO.from_salesforce_record(record) for record in data
|
|
42
41
|
]
|
|
43
42
|
opportunities_list = list(opportunities)
|
|
44
43
|
|
|
@@ -204,7 +204,7 @@ class OpportunityDTO(object):
|
|
|
204
204
|
created_by,
|
|
205
205
|
last_modified_by,
|
|
206
206
|
finance_contact,
|
|
207
|
-
|
|
207
|
+
converted_amount_eur,
|
|
208
208
|
project_code,
|
|
209
209
|
google_drive_link,
|
|
210
210
|
project_status,
|
|
@@ -286,7 +286,7 @@ class OpportunityDTO(object):
|
|
|
286
286
|
self.created_by = created_by
|
|
287
287
|
self.last_modified_by = last_modified_by
|
|
288
288
|
self.finance_contact = finance_contact
|
|
289
|
-
self.
|
|
289
|
+
self.converted_amount_eur = converted_amount_eur
|
|
290
290
|
self.project_code = project_code
|
|
291
291
|
self.google_drive_link = google_drive_link
|
|
292
292
|
self.project_status = project_status
|
|
@@ -380,6 +380,16 @@ class OpportunityDTO(object):
|
|
|
380
380
|
except (KeyError, TypeError):
|
|
381
381
|
return ""
|
|
382
382
|
|
|
383
|
+
def _get_convert_amount():
|
|
384
|
+
try:
|
|
385
|
+
value = record["convertAmount"]
|
|
386
|
+
clean_value = value.replace("EUR", "")
|
|
387
|
+
clean_value = clean_value.replace(",", "")
|
|
388
|
+
|
|
389
|
+
return float(clean_value)
|
|
390
|
+
except (KeyError, TypeError, ValueError):
|
|
391
|
+
return None
|
|
392
|
+
|
|
383
393
|
opportunity_line_items = record.get("OpportunityLineItems", {})
|
|
384
394
|
if opportunity_line_items and isinstance(opportunity_line_items, dict):
|
|
385
395
|
line_items_records = record.get("OpportunityLineItems", {}).get(
|
|
@@ -478,7 +488,9 @@ class OpportunityDTO(object):
|
|
|
478
488
|
record.get("Servicios_Asociados__c", "")
|
|
479
489
|
),
|
|
480
490
|
stage_name=normalize_value(record.get("StageName", "")),
|
|
481
|
-
start_date=normalize_value(
|
|
491
|
+
start_date=normalize_value(
|
|
492
|
+
record.get("DT_ProjectStartDate__c", "")
|
|
493
|
+
),
|
|
482
494
|
tier_short=normalize_value(record.get("Tier_Short__c", "")),
|
|
483
495
|
total_opportunity_quantity=normalize_value(
|
|
484
496
|
record.get("TotalOpportunityQuantity", "")
|
|
@@ -507,9 +519,8 @@ class OpportunityDTO(object):
|
|
|
507
519
|
created_by=_get_created_by(),
|
|
508
520
|
last_modified_by=_get_last_modified_by(),
|
|
509
521
|
finance_contact=record["MAIL_FinanceContact__c"],
|
|
510
|
-
|
|
522
|
+
converted_amount_eur=_get_convert_amount(),
|
|
511
523
|
project_code=record["FRM_ProjectCode__c"],
|
|
512
|
-
|
|
513
524
|
google_drive_link=record["FRM_GoogleDriveLink__c"],
|
|
514
525
|
project_status=record["PCK_ProjectStatus__c"],
|
|
515
526
|
pck_division=record["PCK_Division__c"],
|
|
@@ -593,7 +604,7 @@ class OpportunityDTO(object):
|
|
|
593
604
|
"created_by": self.created_by,
|
|
594
605
|
"last_modified_by": self.last_modified_by,
|
|
595
606
|
"finance_contact": self.finance_contact,
|
|
596
|
-
"
|
|
607
|
+
"converted_amount_eur": self.converted_amount_eur,
|
|
597
608
|
"project_code": self.project_code,
|
|
598
609
|
"google_drive_link": self.google_drive_link,
|
|
599
610
|
"project_status": self.project_status,
|
|
@@ -601,5 +612,4 @@ class OpportunityDTO(object):
|
|
|
601
612
|
"out_of_report": self.out_of_report,
|
|
602
613
|
"billing_info": self.billing_info,
|
|
603
614
|
"parent_opportunity": self.parent_opportunity,
|
|
604
|
-
|
|
605
615
|
}
|
|
@@ -97,12 +97,12 @@ class BigQueryExporter:
|
|
|
97
97
|
"created_by": "STRING",
|
|
98
98
|
"last_modified_by": "STRING",
|
|
99
99
|
"finance_contact": "STRING",
|
|
100
|
-
"
|
|
100
|
+
"converted_amount_eur": "FLOAT",
|
|
101
101
|
"project_code": "STRING",
|
|
102
102
|
"google_drive_link": "STRING",
|
|
103
103
|
"project_status": "STRING",
|
|
104
104
|
"pck_division": "STRING",
|
|
105
|
-
"out_of_report": "
|
|
105
|
+
"out_of_report": "BOOLEAN",
|
|
106
106
|
"billing_info": "STRING",
|
|
107
107
|
"parent_opportunity": "STRING",
|
|
108
108
|
},
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
3
|
+
|
|
4
|
+
from ms_salesforce_api.salesforce.api.project.constants import (
|
|
5
|
+
DEFAULT_PROJECT_BILLING_LINE_QUERY,
|
|
6
|
+
DEFAULT_PROJECT_OPPORTUNITY_QUERY,
|
|
7
|
+
)
|
|
8
|
+
from ms_salesforce_api.salesforce.api.project.dto.BillingLineDTO import (
|
|
9
|
+
BillingLineDTO,
|
|
10
|
+
)
|
|
11
|
+
from ms_salesforce_api.salesforce.api.project.dto.OpportunityDTO import (
|
|
12
|
+
OpportunityDTO,
|
|
13
|
+
)
|
|
14
|
+
from ms_salesforce_api.salesforce.SalesforceQueryExecutor import (
|
|
15
|
+
SalesforceQueryExecutor,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
logging.basicConfig(
|
|
19
|
+
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
MAX_PROJECT_IDS_PER_QUERY = 200
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Project(SalesforceQueryExecutor):
|
|
26
|
+
def fetch_billing_lines(self, project_ids):
|
|
27
|
+
billing_lines = []
|
|
28
|
+
query = DEFAULT_PROJECT_BILLING_LINE_QUERY.format(
|
|
29
|
+
project_id="','".join(project_ids)
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
data = self.fetch_data(query)
|
|
33
|
+
if data is not None:
|
|
34
|
+
billing_lines.extend(data)
|
|
35
|
+
|
|
36
|
+
return billing_lines
|
|
37
|
+
|
|
38
|
+
def get_batches(self, lst, n):
|
|
39
|
+
"""Yield successive n-sized chunks from lst."""
|
|
40
|
+
for i in range(0, len(lst), n):
|
|
41
|
+
yield lst[i : i + n] # noqa: E203
|
|
42
|
+
|
|
43
|
+
def get_all(
|
|
44
|
+
self,
|
|
45
|
+
last_executed_at: str = None,
|
|
46
|
+
query: str = DEFAULT_PROJECT_OPPORTUNITY_QUERY,
|
|
47
|
+
format: str = "json",
|
|
48
|
+
):
|
|
49
|
+
if last_executed_at:
|
|
50
|
+
query = query + f"WHERE CreatedDate > {last_executed_at}"
|
|
51
|
+
|
|
52
|
+
data = self.fetch_data(query)
|
|
53
|
+
if data is None:
|
|
54
|
+
logging.error(
|
|
55
|
+
"[ERROR - SalesforceAPI]: No projects data return from Salesforce API" # noqa: E501
|
|
56
|
+
)
|
|
57
|
+
return []
|
|
58
|
+
|
|
59
|
+
opportunities = {
|
|
60
|
+
record["Id"]: OpportunityDTO.from_salesforce_record(record)
|
|
61
|
+
for record in data
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
project_ids = list(opportunities.keys())
|
|
65
|
+
|
|
66
|
+
with ThreadPoolExecutor(max_workers=10) as executor:
|
|
67
|
+
for project_id_batch in self.get_batches(
|
|
68
|
+
project_ids,
|
|
69
|
+
MAX_PROJECT_IDS_PER_QUERY,
|
|
70
|
+
):
|
|
71
|
+
batch_results = list(
|
|
72
|
+
executor.map(
|
|
73
|
+
self.fetch_billing_lines,
|
|
74
|
+
[project_id_batch],
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
for billing_line_data in batch_results:
|
|
78
|
+
for record in billing_line_data:
|
|
79
|
+
project_id = record["Project_Line_Item__r"][
|
|
80
|
+
"Project__c"
|
|
81
|
+
]
|
|
82
|
+
opportunity = opportunities.get(project_id)
|
|
83
|
+
|
|
84
|
+
billing_line_dto = (
|
|
85
|
+
BillingLineDTO.from_salesforce_record(
|
|
86
|
+
record,
|
|
87
|
+
opportunity.projectcode,
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
if opportunity is not None:
|
|
92
|
+
if not opportunity.billing_lines:
|
|
93
|
+
opportunity.billing_lines = []
|
|
94
|
+
opportunity.billing_lines.append(billing_line_dto)
|
|
95
|
+
opportunities_list = list(opportunities.values())
|
|
96
|
+
if format == "json":
|
|
97
|
+
opportunities_list = [
|
|
98
|
+
opportunity.to_dict() for opportunity in opportunities_list
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
return opportunities_list
|
|
@@ -382,154 +382,152 @@ class TestProject(unittest.TestCase):
|
|
|
382
382
|
self.assertEqual(len(opportunities), 1)
|
|
383
383
|
|
|
384
384
|
opportunity = opportunities[0]
|
|
385
|
-
|
|
385
|
+
opportunity_result = {
|
|
386
|
+
"account_assigment_group": "03",
|
|
387
|
+
"account_billing_address": "211 Main Street, Webster, Maine, 01570, United "
|
|
388
|
+
"States",
|
|
389
|
+
"account_billing_city": "Webster",
|
|
390
|
+
"account_billing_country": "US",
|
|
391
|
+
"account_billing_postal_code": "01570",
|
|
392
|
+
"account_billing_state_code": "ME",
|
|
393
|
+
"account_billing_street": "211 Main Street",
|
|
394
|
+
"account_business_function": "BP03",
|
|
395
|
+
"account_business_name": "THE COMMERCE INSURANCE COMPANY",
|
|
396
|
+
"account_cif": "042495247",
|
|
397
|
+
"account_company_invoicing": "",
|
|
398
|
+
"account_created_date": "2020-03-18 15:32:15",
|
|
399
|
+
"account_currency_code": "EUR",
|
|
400
|
+
"account_customer_groupId": "1",
|
|
401
|
+
"account_customer_subgroupId": "5",
|
|
402
|
+
"account_fax": None,
|
|
403
|
+
"account_invoicing_email": "client1@test.com",
|
|
404
|
+
"account_mail_invoicing": "client1@test.com",
|
|
405
|
+
"account_name": "MAPFRE USA",
|
|
406
|
+
"account_office": "Making Science LLC",
|
|
407
|
+
"account_payment_terms": "T060",
|
|
408
|
+
"account_pec_email": None,
|
|
409
|
+
"account_phone": None,
|
|
410
|
+
"account_sap_id": "10000319",
|
|
411
|
+
"account_tax_category": None,
|
|
412
|
+
"account_tax_classification": "0",
|
|
413
|
+
"account_tax_id_type": "US01",
|
|
414
|
+
"account_tier": "T1",
|
|
415
|
+
"account_website": None,
|
|
416
|
+
"amount": 0.0,
|
|
417
|
+
"autorenewal": False,
|
|
418
|
+
"billing_lines": [
|
|
419
|
+
{
|
|
420
|
+
"billing_amount": 6708.0,
|
|
421
|
+
"billing_date": "2022-08-31",
|
|
422
|
+
"billing_period_ending_date": "2022-08-31",
|
|
423
|
+
"billing_period_starting_date": "2022-08-01",
|
|
424
|
+
"billing_plan_amount": "6708",
|
|
425
|
+
"billing_plan_billing_date": "2022-08-31",
|
|
426
|
+
"billing_plan_item": "1",
|
|
427
|
+
"billing_plan_service_end_date": "2022-08-31",
|
|
428
|
+
"billing_plan_service_start_date": "2022-08-01",
|
|
429
|
+
"created_date": "2022-08-09 14:56:23",
|
|
430
|
+
"currency": "USD",
|
|
431
|
+
"hourly_price": 65.0,
|
|
432
|
+
"id": "a0sAX000000I8lgYAC",
|
|
433
|
+
"last_modified_date": "2022-10-16 18:56:34",
|
|
434
|
+
"name": "BL-000175313",
|
|
435
|
+
"project_code": "",
|
|
436
|
+
"project_id": "a00AX000002DVi1YAG",
|
|
437
|
+
"revenue_dedication": 103.2,
|
|
438
|
+
}
|
|
439
|
+
],
|
|
440
|
+
"comments": "",
|
|
441
|
+
"controller_email": "employee4@test.com",
|
|
442
|
+
"controller_sub_email": "employee3@test.com",
|
|
443
|
+
"cost_center": "",
|
|
444
|
+
"created_at": "2022-08-01 08:53:12",
|
|
445
|
+
"currency": "EUR",
|
|
446
|
+
"end_date": "",
|
|
447
|
+
"group_bqid": "1",
|
|
448
|
+
"group_end_date": "2100-12-12",
|
|
449
|
+
"group_groupid": "a0cAX000000TSWUYA4",
|
|
450
|
+
"group_name": "MAPFRE",
|
|
451
|
+
"group_owner_email": "employee1@test.com",
|
|
452
|
+
"group_pck_type": "Key Account",
|
|
453
|
+
"group_start_date": "2023-06-01",
|
|
454
|
+
"group_supervisor_email": "employee2@test.com",
|
|
455
|
+
"international_deparments": False,
|
|
456
|
+
"invoicing_country_code": "US",
|
|
457
|
+
"jira_task_url": "<a "
|
|
458
|
+
"href=https://makingscience.atlassian.net/browse/ESMSBD0001-7168 "
|
|
459
|
+
"target=_blank>View Jira Task</a>",
|
|
460
|
+
"last_updated_at": "2023-09-01 10:00:54",
|
|
461
|
+
"maintance_project": False,
|
|
462
|
+
"ms_project_id": False,
|
|
463
|
+
"operation_coordinator_email": "employee5@test.com",
|
|
464
|
+
"operation_coordinator_name": "",
|
|
465
|
+
"operation_coordinator_sub": "",
|
|
466
|
+
"operation_coordinator_sub_email": "employee5@test.com",
|
|
467
|
+
"opportunity": "",
|
|
468
|
+
"opportunity_extension": "",
|
|
469
|
+
"opportunity_name": "New Site Mapfre AAA",
|
|
470
|
+
"opportunity_project_code": "",
|
|
471
|
+
"periodicity": "",
|
|
472
|
+
"profit_center": "200018",
|
|
473
|
+
"profitcenter": "",
|
|
474
|
+
"project_account": "",
|
|
475
|
+
"project_id": "a00AX000002DVi1YAG",
|
|
476
|
+
"project_line_items": [
|
|
477
|
+
{
|
|
478
|
+
"country": None,
|
|
479
|
+
"created_date": "2022-08-02 15:44:34",
|
|
480
|
+
"effort": "516",
|
|
481
|
+
"ending_date": "2022-12-31",
|
|
482
|
+
"id": "a0VAX000000EE0b2AG",
|
|
483
|
+
"last_modified_date": "2023-06-20 22:33:36",
|
|
484
|
+
"ms_pli_name": "USA_UX/UI Design_USMSEX05508",
|
|
485
|
+
"opportunity_project_code": None,
|
|
486
|
+
"product_name": "UXUI Project",
|
|
487
|
+
"project_id": "a00AX000002DVi1YAG",
|
|
488
|
+
"quantity": 516.0,
|
|
489
|
+
"starting_date": "2022-08-01",
|
|
490
|
+
"total_price": 33540.0,
|
|
491
|
+
"unit_price": 65.0,
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
"country": None,
|
|
495
|
+
"created_date": "2022-08-09 14:54:59",
|
|
496
|
+
"effort": "331",
|
|
497
|
+
"ending_date": "2022-12-31",
|
|
498
|
+
"id": "a0VAX000000ELU52AO",
|
|
499
|
+
"last_modified_date": "2023-06-20 22:33:36",
|
|
500
|
+
"ms_pli_name": "ES_UX/UI Design_USMSEX05508",
|
|
501
|
+
"opportunity_project_code": None,
|
|
502
|
+
"product_name": "UXUI Project",
|
|
503
|
+
"project_id": "a00AX000002DVi1YAG",
|
|
504
|
+
"quantity": 331.0,
|
|
505
|
+
"starting_date": "2022-08-01",
|
|
506
|
+
"total_price": 21515.0,
|
|
507
|
+
"unit_price": 65.0,
|
|
508
|
+
},
|
|
509
|
+
],
|
|
510
|
+
"project_name": "MapfreAAA",
|
|
511
|
+
"project_start_date": "2022-08-01",
|
|
512
|
+
"project_tier": "Unkown",
|
|
513
|
+
"projectcode": "",
|
|
514
|
+
"quote": "",
|
|
515
|
+
"revenue_details": "",
|
|
516
|
+
"status": "",
|
|
517
|
+
"subgroup_bqid": "5",
|
|
518
|
+
"subgroup_end_date": "2100-12-12",
|
|
519
|
+
"subgroup_groupid": "a0cAX000000TSWUYA4",
|
|
520
|
+
"subgroup_name": "MAPFRE USA",
|
|
521
|
+
"subgroup_owner_email": "employee1@test.com",
|
|
522
|
+
"subgroup_start_date": "2023-06-01",
|
|
523
|
+
"subgroup_subgroupid": "a19AX0000004simYAA",
|
|
524
|
+
}
|
|
386
525
|
self.assertIsInstance(opportunity, dict)
|
|
387
526
|
|
|
388
527
|
self.assertDictEqual(
|
|
389
528
|
opportunity,
|
|
390
|
-
|
|
391
|
-
"account_assigment_group": "03",
|
|
392
|
-
"account_billing_address": "211 Main Street, Webster, Maine, 01570, United "
|
|
393
|
-
"States",
|
|
394
|
-
"account_billing_city": "Webster",
|
|
395
|
-
"account_billing_country": "US",
|
|
396
|
-
"account_billing_postal_code": "01570",
|
|
397
|
-
"account_billing_state_code": "ME",
|
|
398
|
-
"account_billing_street": "211 Main Street",
|
|
399
|
-
"account_business_function": "BP03",
|
|
400
|
-
"account_business_name": "THE COMMERCE INSURANCE COMPANY",
|
|
401
|
-
"account_cif": "042495247",
|
|
402
|
-
"account_company_invoicing": "",
|
|
403
|
-
"account_created_date": "2020-03-18 15:32:15",
|
|
404
|
-
"account_currency_code": "EUR",
|
|
405
|
-
"account_customer_groupId": "1",
|
|
406
|
-
"account_customer_subgroupId": "5",
|
|
407
|
-
"account_fax": None,
|
|
408
|
-
"account_invoicing_email": "client1@test.com",
|
|
409
|
-
"account_mail_invoicing": "client1@test.com",
|
|
410
|
-
"account_name": "MAPFRE USA",
|
|
411
|
-
"account_office": "Making Science LLC",
|
|
412
|
-
"account_payment_terms": "T060",
|
|
413
|
-
"account_pec_email": None,
|
|
414
|
-
"account_phone": None,
|
|
415
|
-
"account_sap_id": "10000319",
|
|
416
|
-
"account_tax_category": None,
|
|
417
|
-
"account_tax_classification": "0",
|
|
418
|
-
"account_tax_id_type": "US01",
|
|
419
|
-
"account_tier": "T1",
|
|
420
|
-
"account_website": None,
|
|
421
|
-
"amount": 0.0,
|
|
422
|
-
"autorenewal": False,
|
|
423
|
-
"billing_lines": [
|
|
424
|
-
{
|
|
425
|
-
"billing_amount": 6708.0,
|
|
426
|
-
"billing_date": "2022-08-31",
|
|
427
|
-
"billing_period_ending_date": "2022-08-31",
|
|
428
|
-
"billing_period_starting_date": "2022-08-01",
|
|
429
|
-
"billing_plan_amount": "6708",
|
|
430
|
-
"billing_plan_billing_date": "2022-08-31",
|
|
431
|
-
"billing_plan_item": "1",
|
|
432
|
-
"billing_plan_service_end_date": "2022-08-31",
|
|
433
|
-
"billing_plan_service_start_date": "2022-08-01",
|
|
434
|
-
"created_date": "2022-08-09 14:56:23",
|
|
435
|
-
"currency": "USD",
|
|
436
|
-
"hourly_price": 65.0,
|
|
437
|
-
"id": "a0sAX000000I8lgYAC",
|
|
438
|
-
"last_modified_date": "2022-10-16 18:56:34",
|
|
439
|
-
"name": "BL-000175313",
|
|
440
|
-
"project_code": "USMSEX05508",
|
|
441
|
-
"project_id": "a00AX000002DVi1YAG",
|
|
442
|
-
"revenue_dedication": 103.2,
|
|
443
|
-
}
|
|
444
|
-
],
|
|
445
|
-
"comments": "",
|
|
446
|
-
"controller_email": "employee4@test.com",
|
|
447
|
-
"controller_sub_email": "employee3@test.com",
|
|
448
|
-
"cost_center": "",
|
|
449
|
-
"created_at": "2022-08-01 08:53:12",
|
|
450
|
-
"currency": "EUR",
|
|
451
|
-
"end_date": "",
|
|
452
|
-
"group_bqid": "1",
|
|
453
|
-
"group_end_date": "2100-12-12",
|
|
454
|
-
"group_groupid": "a0cAX000000TSWUYA4",
|
|
455
|
-
"group_name": "MAPFRE",
|
|
456
|
-
"group_owner_email": "employee1@test.com",
|
|
457
|
-
"group_pck_type": "Key Account",
|
|
458
|
-
"group_start_date": "2023-06-01",
|
|
459
|
-
"group_supervisor_email": "employee2@test.com",
|
|
460
|
-
"international_deparments": False,
|
|
461
|
-
"invoicing_country_code": "US",
|
|
462
|
-
"jira_task_url": "<a "
|
|
463
|
-
"href=https://makingscience.atlassian.net/browse/ESMSBD0001-7168 "
|
|
464
|
-
"target=_blank>View Jira Task</a>",
|
|
465
|
-
"last_updated_at": "2023-09-01 10:00:54",
|
|
466
|
-
"maintance_project": False,
|
|
467
|
-
"ms_project_id": False,
|
|
468
|
-
"operation_coordinator_email": "employee5@test.com",
|
|
469
|
-
"operation_coordinator_name": "",
|
|
470
|
-
"operation_coordinator_sub": "",
|
|
471
|
-
"operation_coordinator_sub_email": "employee5@test.com",
|
|
472
|
-
"opportunity": "",
|
|
473
|
-
"opportunity_extension": "",
|
|
474
|
-
"opportunity_name": "New Site Mapfre AAA",
|
|
475
|
-
"periodicity": "",
|
|
476
|
-
"profit_center": "200018",
|
|
477
|
-
"profitcenter": "",
|
|
478
|
-
"project_account": "",
|
|
479
|
-
"project_code": "USMSEX05508",
|
|
480
|
-
"project_id": "a00AX000002DVi1YAG",
|
|
481
|
-
"project_line_items": [
|
|
482
|
-
{
|
|
483
|
-
"country": None,
|
|
484
|
-
"created_date": "2022-08-02 15:44:34",
|
|
485
|
-
"effort": "516",
|
|
486
|
-
"ending_date": "2022-12-31",
|
|
487
|
-
"id": "a0VAX000000EE0b2AG",
|
|
488
|
-
"last_modified_date": "2023-06-20 22:33:36",
|
|
489
|
-
"ms_pli_name": "USA_UX/UI Design_USMSEX05508",
|
|
490
|
-
"ms_project_code": None,
|
|
491
|
-
"product_name": "UXUI Project",
|
|
492
|
-
"project_id": "a00AX000002DVi1YAG",
|
|
493
|
-
"quantity": 516.0,
|
|
494
|
-
"starting_date": "2022-08-01",
|
|
495
|
-
"total_price": 33540.0,
|
|
496
|
-
"unit_price": 65.0,
|
|
497
|
-
},
|
|
498
|
-
{
|
|
499
|
-
"country": None,
|
|
500
|
-
"created_date": "2022-08-09 14:54:59",
|
|
501
|
-
"effort": "331",
|
|
502
|
-
"ending_date": "2022-12-31",
|
|
503
|
-
"id": "a0VAX000000ELU52AO",
|
|
504
|
-
"last_modified_date": "2023-06-20 22:33:36",
|
|
505
|
-
"ms_pli_name": "ES_UX/UI Design_USMSEX05508",
|
|
506
|
-
"ms_project_code": None,
|
|
507
|
-
"product_name": "UXUI Project",
|
|
508
|
-
"project_id": "a00AX000002DVi1YAG",
|
|
509
|
-
"quantity": 331.0,
|
|
510
|
-
"starting_date": "2022-08-01",
|
|
511
|
-
"total_price": 21515.0,
|
|
512
|
-
"unit_price": 65.0,
|
|
513
|
-
},
|
|
514
|
-
],
|
|
515
|
-
"project_name": "MapfreAAA",
|
|
516
|
-
"project_start_date": "2022-08-01",
|
|
517
|
-
"project_tier": "Unkown",
|
|
518
|
-
"projectcode": "",
|
|
519
|
-
"projectid": "",
|
|
520
|
-
"quote": "",
|
|
521
|
-
"revenue_details": "",
|
|
522
|
-
"status": "",
|
|
523
|
-
"subgroup_bqid": "5",
|
|
524
|
-
"subgroup_end_date": "2100-12-12",
|
|
525
|
-
"subgroup_groupid": "a0cAX000000TSWUYA4",
|
|
526
|
-
"subgroup_name": "MAPFRE USA",
|
|
527
|
-
"subgroup_owner_email": "employee1@test.com",
|
|
528
|
-
"subgroup_start_date": "2023-06-01",
|
|
529
|
-
"subgroup_subgroupid": "a19AX0000004simYAA",
|
|
530
|
-
},
|
|
529
|
+
opportunity_result,
|
|
531
530
|
)
|
|
532
|
-
|
|
533
531
|
billing_line = opportunity["billing_lines"][0]
|
|
534
532
|
self.assertDictEqual(
|
|
535
533
|
billing_line,
|
|
@@ -549,7 +547,7 @@ class TestProject(unittest.TestCase):
|
|
|
549
547
|
"id": "a0sAX000000I8lgYAC",
|
|
550
548
|
"last_modified_date": "2022-10-16 18:56:34",
|
|
551
549
|
"name": "BL-000175313",
|
|
552
|
-
"project_code": "
|
|
550
|
+
"project_code": "",
|
|
553
551
|
"project_id": "a00AX000002DVi1YAG",
|
|
554
552
|
"revenue_dedication": 103.2,
|
|
555
553
|
},
|
|
@@ -546,7 +546,9 @@ class OpportunityDTO(object):
|
|
|
546
546
|
|
|
547
547
|
def _get_opportunity_project_code():
|
|
548
548
|
try:
|
|
549
|
-
return normalize_value(
|
|
549
|
+
return normalize_value(
|
|
550
|
+
record["Opportunity__r"]["FRM_ProjectCode__c"]
|
|
551
|
+
)
|
|
550
552
|
except (TypeError, KeyError):
|
|
551
553
|
return ""
|
|
552
554
|
|
|
@@ -47,11 +47,25 @@ class ProjectLineItemDTO:
|
|
|
47
47
|
except Exception:
|
|
48
48
|
return ""
|
|
49
49
|
|
|
50
|
+
def _get_opportunity_project_code():
|
|
51
|
+
try:
|
|
52
|
+
project = record.get("Project__r")
|
|
53
|
+
opportunity = project.get("Opportunity__r") if project else {}
|
|
54
|
+
opportunity_project_code = opportunity.get(
|
|
55
|
+
"FRM_ProjectCode__c"
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
return opportunity_project_code
|
|
59
|
+
|
|
60
|
+
except AttributeError:
|
|
61
|
+
return None
|
|
62
|
+
|
|
50
63
|
product_name = (
|
|
51
64
|
record.get("ProductNew__r", {}).get("Name")
|
|
52
65
|
if record.get("ProductNew__r")
|
|
53
66
|
else None
|
|
54
67
|
)
|
|
68
|
+
|
|
55
69
|
return cls(
|
|
56
70
|
id=record.get("Id"),
|
|
57
71
|
created_date=_parse_created_date(record.get("CreatedDate")),
|
|
@@ -68,7 +82,7 @@ class ProjectLineItemDTO:
|
|
|
68
82
|
ms_pli_name=record.get("MS_PLI_Name__c"),
|
|
69
83
|
country=record.get("Country__c"),
|
|
70
84
|
project_id=project_id,
|
|
71
|
-
opportunity_project_code=
|
|
85
|
+
opportunity_project_code=_get_opportunity_project_code(),
|
|
72
86
|
)
|
|
73
87
|
|
|
74
88
|
def to_dict(self):
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from concurrent.futures import ThreadPoolExecutor
|
|
3
|
-
|
|
4
|
-
from ms_salesforce_api.salesforce.api.project.constants import (
|
|
5
|
-
DEFAULT_PROJECT_BILLING_LINE_QUERY,
|
|
6
|
-
DEFAULT_PROJECT_OPPORTUNITY_QUERY,
|
|
7
|
-
)
|
|
8
|
-
from ms_salesforce_api.salesforce.api.project.dto.BillingLineDTO import (
|
|
9
|
-
BillingLineDTO,
|
|
10
|
-
)
|
|
11
|
-
from ms_salesforce_api.salesforce.api.project.dto.OpportunityDTO import (
|
|
12
|
-
OpportunityDTO,
|
|
13
|
-
)
|
|
14
|
-
from ms_salesforce_api.salesforce.SalesforceQueryExecutor import (
|
|
15
|
-
SalesforceQueryExecutor,
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
logging.basicConfig(
|
|
19
|
-
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
MAX_PROJECT_IDS_PER_QUERY = 200
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class Project(SalesforceQueryExecutor):
|
|
26
|
-
def fetch_billing_lines(self, project_ids):
|
|
27
|
-
billing_lines = []
|
|
28
|
-
query = DEFAULT_PROJECT_BILLING_LINE_QUERY.format(
|
|
29
|
-
project_id="','".join(project_ids)
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
data = self.fetch_data(query)
|
|
33
|
-
if data is not None:
|
|
34
|
-
billing_lines.extend(data)
|
|
35
|
-
|
|
36
|
-
return billing_lines
|
|
37
|
-
|
|
38
|
-
def get_batches(self, lst, n):
|
|
39
|
-
"""Yield successive n-sized chunks from lst."""
|
|
40
|
-
for i in range(0, len(lst), n):
|
|
41
|
-
yield lst[i : i + n] # noqa: E203
|
|
42
|
-
|
|
43
|
-
def get_all(
|
|
44
|
-
self,
|
|
45
|
-
last_executed_at: str = None,
|
|
46
|
-
query: str = DEFAULT_PROJECT_OPPORTUNITY_QUERY,
|
|
47
|
-
format: str = "json",
|
|
48
|
-
):
|
|
49
|
-
try:
|
|
50
|
-
if last_executed_at:
|
|
51
|
-
query = query + f"WHERE CreatedDate > {last_executed_at}"
|
|
52
|
-
|
|
53
|
-
data = self.fetch_data(query)
|
|
54
|
-
if data is None:
|
|
55
|
-
logging.error(
|
|
56
|
-
"[ERROR - SalesforceAPI]: No projects data return from Salesforce API" # noqa: E501
|
|
57
|
-
)
|
|
58
|
-
return []
|
|
59
|
-
|
|
60
|
-
opportunities = {
|
|
61
|
-
record["Id"]: OpportunityDTO.from_salesforce_record(record)
|
|
62
|
-
for record in data
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
project_ids = list(opportunities.keys())
|
|
66
|
-
|
|
67
|
-
with ThreadPoolExecutor(max_workers=10) as executor:
|
|
68
|
-
for project_id_batch in self.get_batches(
|
|
69
|
-
project_ids,
|
|
70
|
-
MAX_PROJECT_IDS_PER_QUERY,
|
|
71
|
-
):
|
|
72
|
-
batch_results = list(
|
|
73
|
-
executor.map(
|
|
74
|
-
self.fetch_billing_lines,
|
|
75
|
-
[project_id_batch],
|
|
76
|
-
)
|
|
77
|
-
)
|
|
78
|
-
for billing_line_data in batch_results:
|
|
79
|
-
for record in billing_line_data:
|
|
80
|
-
project_id = record["Project_Line_Item__r"][
|
|
81
|
-
"Project__c"
|
|
82
|
-
]
|
|
83
|
-
opportunity = opportunities.get(project_id)
|
|
84
|
-
|
|
85
|
-
billing_line_dto = (
|
|
86
|
-
BillingLineDTO.from_salesforce_record(
|
|
87
|
-
record,
|
|
88
|
-
opportunity.projectcode,
|
|
89
|
-
)
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
if opportunity is not None:
|
|
93
|
-
if not opportunity.billing_lines:
|
|
94
|
-
opportunity.billing_lines = []
|
|
95
|
-
opportunity.billing_lines.append(
|
|
96
|
-
billing_line_dto
|
|
97
|
-
)
|
|
98
|
-
opportunities_list = list(opportunities.values())
|
|
99
|
-
if format == "json":
|
|
100
|
-
opportunities_list = [
|
|
101
|
-
opportunity.to_dict() for opportunity in opportunities_list
|
|
102
|
-
]
|
|
103
|
-
|
|
104
|
-
return opportunities_list
|
|
105
|
-
except Exception as e:
|
|
106
|
-
logging.error(
|
|
107
|
-
f"[ERROR - get_all]: Failed to get opportunities: {e}"
|
|
108
|
-
)
|
|
109
|
-
return []
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/Auth.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ms_salesforce_api-2.24.0.dev5 → ms_salesforce_api-3.0.0}/ms_salesforce_api/salesforce/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|