merging with upstream
This commit is contained in:
@@ -44,9 +44,10 @@ AWS_S3_BUCKET="..."
|
|||||||
AWS_ACCESS_KEY_ID="..."
|
AWS_ACCESS_KEY_ID="..."
|
||||||
AWS_SECRET_ACCESS_KEY="..."
|
AWS_SECRET_ACCESS_KEY="..."
|
||||||
|
|
||||||
SF_BASE_URL="https://test.salesforce.com"
|
SFDC_BASE_URL="https://test.salesforce.com"
|
||||||
SFDC_ACCESS_KEY_ID="..."
|
SFDC_ACCESS_KEY_ID="..."
|
||||||
SFDC_SECRET_ACCESS_KEY="..."
|
SFDC_SECRET_ACCESS_KEY="..."
|
||||||
|
SFDC_API_URL="https://sunpower--qa.cs8.my.salesforce.com"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ def s3_upload(bytes_or_file_like, filename=None, file_extension=None):
|
|||||||
|
|
||||||
# Assuming bucket already exists
|
# Assuming bucket already exists
|
||||||
s3.Bucket(bucket_name).put_object(Key=filename, Body=bytes_or_file_like.read(), ACL='public-read')
|
s3.Bucket(bucket_name).put_object(Key=filename, Body=bytes_or_file_like.read(), ACL='public-read')
|
||||||
file_url = 'https://s3.amazonaws.com/{}/{}'.format(bucket_name, filename)
|
# file_url = 'https://s3.amazonaws.com/{}/{}'.format(bucket_name, filename) # PermanentRedirect error
|
||||||
|
file_url = 'https://{}.s3.amazonaws.com/{}'.format(bucket_name, filename)
|
||||||
print('Uploaded filename {} to S3: {}'.format(filename, file_url))
|
print('Uploaded filename {} to S3: {}'.format(filename, file_url))
|
||||||
return file_url
|
return file_url
|
||||||
|
|||||||
@@ -5,12 +5,18 @@ except ImportError:
|
|||||||
|
|
||||||
|
|
||||||
class JsonBuilder:
|
class JsonBuilder:
|
||||||
def build_bom_output(self, rows):
|
def build_bom(self, rows):
|
||||||
data = []
|
data = []
|
||||||
headers = ['Part #', 'Description', 'Total']
|
headers = ['itemId', 'description', 'quantity']
|
||||||
for row in rows:
|
for row in rows:
|
||||||
d = {}
|
d = {}
|
||||||
for i, value in enumerate(row):
|
for i, value in enumerate(row):
|
||||||
d[headers[i]] = value
|
d[headers[i]] = value
|
||||||
data.append(d)
|
data.append(d)
|
||||||
|
return data
|
||||||
|
|
||||||
|
def bom_to_json(self, data):
|
||||||
return json.dumps(data)
|
return json.dumps(data)
|
||||||
|
|
||||||
|
def build_bom_output(self, rows):
|
||||||
|
return self.bom_to_json(self.build_bom(rows))
|
||||||
|
|||||||
@@ -41,16 +41,21 @@ app.config['PROFILE'] = True
|
|||||||
|
|
||||||
# Sales Force integrations
|
# Sales Force integrations
|
||||||
oauth = OAuth()
|
oauth = OAuth()
|
||||||
SF_BASE_URL = os.getenv('SFDC_BASE_URL', 'https://test.salesforce.com')
|
SFDC_BASE_URL = os.getenv('SFDC_BASE_URL', 'https://test.salesforce.com')
|
||||||
sales_force = oauth.remote_app('sales_force',
|
try:
|
||||||
consumer_key=os.getenv('SFDC_ACCESS_KEY_ID'),
|
sales_force = oauth.remote_app('sales_force',
|
||||||
consumer_secret=os.getenv('SFDC_SECRET_ACCESS_KEY'),
|
consumer_key=os.getenv('SFDC_ACCESS_KEY_ID'),
|
||||||
base_url=SF_BASE_URL,
|
consumer_secret=os.getenv('SFDC_SECRET_ACCESS_KEY'),
|
||||||
request_token_url=None, # OAuth 2
|
base_url=SFDC_BASE_URL,
|
||||||
access_token_method='POST', # Sales Force requirement
|
request_token_url=None, # OAuth 2
|
||||||
access_token_url=SF_BASE_URL + '/services/oauth2/token',
|
access_token_method='POST', # Sales Force requirement
|
||||||
authorize_url=SF_BASE_URL + '/services/oauth2/authorize',
|
access_token_url=SFDC_BASE_URL + '/services/oauth2/token',
|
||||||
)
|
authorize_url=SFDC_BASE_URL + '/services/oauth2/authorize',
|
||||||
|
)
|
||||||
|
except TypeError:
|
||||||
|
print('Sales Force integration disabled')
|
||||||
|
sales_force = None
|
||||||
|
|
||||||
|
|
||||||
assets_env = assets.Environment(app)
|
assets_env = assets.Environment(app)
|
||||||
assets_env.init_app(app)
|
assets_env.init_app(app)
|
||||||
@@ -186,7 +191,7 @@ def summary():
|
|||||||
return render_template('site_summary.html.jinja', context=context)
|
return render_template('site_summary.html.jinja', context=context)
|
||||||
|
|
||||||
|
|
||||||
def handle_dxf_file(session_manager, file_contents, filename=None):
|
def handle_dxf_file(session_manager, file_contents, filename=None, save_file=True):
|
||||||
errors = []
|
errors = []
|
||||||
user_values = session_manager.user_values()
|
user_values = session_manager.user_values()
|
||||||
validator = FileValidator(user_values)
|
validator = FileValidator(user_values)
|
||||||
@@ -210,7 +215,8 @@ def handle_dxf_file(session_manager, file_contents, filename=None):
|
|||||||
DXFHelper(),
|
DXFHelper(),
|
||||||
SubarrayValidator())
|
SubarrayValidator())
|
||||||
csv = CsvBuilder().build_cad_output(dxf_data['panels'])
|
csv = CsvBuilder().build_cad_output(dxf_data['panels'])
|
||||||
session_manager.save_uploaded_file(csv, dxf_file_name=filename)
|
if save_file:
|
||||||
|
session_manager.save_uploaded_file(csv, dxf_file_name=filename)
|
||||||
|
|
||||||
buildings = dxf_data['buildings']
|
buildings = dxf_data['buildings']
|
||||||
session_manager.save_buildings_polygons(buildings)
|
session_manager.save_buildings_polygons(buildings)
|
||||||
@@ -334,7 +340,7 @@ def load_dxf_file():
|
|||||||
db_session = sql_constant.sql_session_maker()
|
db_session = sql_constant.sql_session_maker()
|
||||||
session_manager = SessionManager(session, redis_constant.redis_store, db_session)
|
session_manager = SessionManager(session, redis_constant.redis_store, db_session)
|
||||||
|
|
||||||
success, errors = handle_dxf_file(session_manager, file_contents, filename=filename)
|
success, errors = handle_dxf_file(session_manager, file_contents, filename=filename, save_file=False)
|
||||||
session['dxf_link_loaded'] = True
|
session['dxf_link_loaded'] = True
|
||||||
if success:
|
if success:
|
||||||
return jsonify({'status': 'success'})
|
return jsonify({'status': 'success'})
|
||||||
@@ -424,6 +430,10 @@ def download():
|
|||||||
session_manager = SessionManager(session, redis_constant.redis_store, db_session)
|
session_manager = SessionManager(session, redis_constant.redis_store, db_session)
|
||||||
context = session_manager.context()
|
context = session_manager.context()
|
||||||
context['current_step'] = 5
|
context['current_step'] = 5
|
||||||
|
error, data = session.pop('sfdc_export_urls', (None, None))
|
||||||
|
if data is not None:
|
||||||
|
context['sfdc_export_error'] = error
|
||||||
|
context['sfdc_export_urls'] = data
|
||||||
db_session.close()
|
db_session.close()
|
||||||
return render_template('download.html.jinja', context=context)
|
return render_template('download.html.jinja', context=context)
|
||||||
|
|
||||||
@@ -540,7 +550,7 @@ def sales_force_authorized():
|
|||||||
session_manager = SessionManager(session, redis_constant.redis_store, db_session)
|
session_manager = SessionManager(session, redis_constant.redis_store, db_session)
|
||||||
session['sales_force_token'] = resp['access_token']
|
session['sales_force_token'] = resp['access_token']
|
||||||
|
|
||||||
data = sf_tasks.get_site_characterization_from_sales_force(session, resp['instance_url'])
|
data = sf_tasks.get_site_characterization_from_sales_force(session)
|
||||||
if data:
|
if data:
|
||||||
session['dxf_link'] = data['dxf_link']
|
session['dxf_link'] = data['dxf_link']
|
||||||
session_manager.save_form_submission(data)
|
session_manager.save_form_submission(data)
|
||||||
@@ -549,23 +559,27 @@ def sales_force_authorized():
|
|||||||
return sales_force_logout()
|
return sales_force_logout()
|
||||||
|
|
||||||
|
|
||||||
# FIXME
|
|
||||||
@app.route("/export-sfdc")
|
@app.route("/export-sfdc")
|
||||||
def export_sfdc():
|
def export_sfdc():
|
||||||
if not is_sfdc_session():
|
if not is_sfdc_session():
|
||||||
return redirect('/')
|
return redirect('/')
|
||||||
db_session = sql_constant.sql_session_maker()
|
db_session = sql_constant.sql_session_maker()
|
||||||
session_manager = SessionManager(session, redis_constant.redis_store, db_session)
|
session_manager = SessionManager(session, redis_constant.redis_store, db_session)
|
||||||
session_id = session_manager.session['id']
|
helix_session_id = session_manager.session['id']
|
||||||
data = sf_tasks.export_to_sfdc(session_id)
|
access_token = session['sales_force_token']
|
||||||
|
sfid = session['SFID']
|
||||||
|
error, data = sf_tasks.export_to_sfdc(helix_session_id, access_token, sfid)
|
||||||
|
data.pop('bom', None)
|
||||||
|
data['dxfUrlFromSF'] = session['dxf_link']
|
||||||
|
session['sfdc_export_urls'] = (error, data)
|
||||||
db_session.close()
|
db_session.close()
|
||||||
return jsonify(data)
|
return redirect('/download')
|
||||||
# return redirect('/download')
|
|
||||||
|
|
||||||
|
|
||||||
@sales_force.tokengetter
|
if sales_force:
|
||||||
def get_sales_force_token(token=None):
|
@sales_force.tokengetter
|
||||||
return session.get('sales_force_token')
|
def get_sales_force_token(token=None):
|
||||||
|
return session.get('sales_force_token')
|
||||||
|
|
||||||
|
|
||||||
@app.route('/sales_force_logout')
|
@app.route('/sales_force_logout')
|
||||||
@@ -574,6 +588,7 @@ def sales_force_logout():
|
|||||||
session.pop('sales_force_token', None)
|
session.pop('sales_force_token', None)
|
||||||
session.pop('dxf_link', None)
|
session.pop('dxf_link', None)
|
||||||
session.pop('dxf_link_loaded', None)
|
session.pop('dxf_link_loaded', None)
|
||||||
|
session.pop('sfdc_export_urls', None)
|
||||||
session.clear()
|
session.clear()
|
||||||
return redirect('/')
|
return redirect('/')
|
||||||
# End of Sales Force Integration
|
# End of Sales Force Integration
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class ProjectPresenter(object):
|
|||||||
# origin = self.find_origin(building)
|
# origin = self.find_origin(building)
|
||||||
for point in building:
|
for point in building:
|
||||||
point.x = point.x * spacing_x
|
point.x = point.x * spacing_x
|
||||||
point.y = abs((point.y * spacing_y - max_y))
|
point.y = abs((point.y * spacing_y) - max_y)
|
||||||
presentable_building.append(point.__dict__)
|
presentable_building.append(point.__dict__)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import io
|
import io
|
||||||
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
@@ -16,14 +17,12 @@ from helix.Services.s3_helper import s3_upload
|
|||||||
from helix.session_manager import SessionManager
|
from helix.session_manager import SessionManager
|
||||||
|
|
||||||
|
|
||||||
def get_site_characterization_from_sales_force(session, base_url):
|
def get_site_characterization_from_sales_force(session):
|
||||||
'''
|
|
||||||
@base_url: Avoid URL_NOT_RESET errors
|
|
||||||
'''
|
|
||||||
access_token = session['sales_force_token']
|
access_token = session['sales_force_token']
|
||||||
sfid = session['SFID']
|
sfid = session['SFID']
|
||||||
helix_id = session['id']
|
helix_id = session['id']
|
||||||
url = base_url + '/services/apexrest/v1/HelixRoofDetails'
|
SFDC_API_URL = os.getenv('SFDC_API_URL', 'https://sunpower--qa.cs8.my.salesforce.com')
|
||||||
|
url = SFDC_API_URL + '/services/apexrest/v1/HelixRoofDetails'
|
||||||
headers = {'Authorization': 'Bearer {}'.format(access_token)}
|
headers = {'Authorization': 'Bearer {}'.format(access_token)}
|
||||||
result = requests.get(url, headers=headers, params={'SFID': sfid, 'helix_session_id': helix_id})
|
result = requests.get(url, headers=headers, params={'SFID': sfid, 'helix_session_id': helix_id})
|
||||||
if result.status_code == 200:
|
if result.status_code == 200:
|
||||||
@@ -50,12 +49,12 @@ def convert_sales_force_data_format_to_helix(data):
|
|||||||
# data['spectral_response_acceleration']
|
# data['spectral_response_acceleration']
|
||||||
|
|
||||||
|
|
||||||
def export_to_sfdc(session_id):
|
def export_to_sfdc(helix_session_id, access_token, sfid):
|
||||||
step = 'Exporting to SFDC'
|
step = 'Exporting to SFDC'
|
||||||
try:
|
try:
|
||||||
# 1. Load User Values
|
# 1. Load User Values
|
||||||
step = 'Loading User Values'
|
step = 'Loading User Values'
|
||||||
session = {'id': session_id}
|
session = {'id': helix_session_id}
|
||||||
db_session = sql_constant.sql_session_maker()
|
db_session = sql_constant.sql_session_maker()
|
||||||
session_manager = SessionManager(session, redis_constant.redis_store, db_session)
|
session_manager = SessionManager(session, redis_constant.redis_store, db_session)
|
||||||
user_values = session_manager.user_values()
|
user_values = session_manager.user_values()
|
||||||
@@ -67,7 +66,9 @@ def export_to_sfdc(session_id):
|
|||||||
csv_file = CsvBuilder().build_bom_output(bom)
|
csv_file = CsvBuilder().build_bom_output(bom)
|
||||||
# 2.1 Generate BOM CSV file
|
# 2.1 Generate BOM CSV file
|
||||||
step = 'Generating BOM as JSON'
|
step = 'Generating BOM as JSON'
|
||||||
json_str = JsonBuilder().build_bom_output(bom)
|
json_builder = JsonBuilder()
|
||||||
|
bom_list = json_builder.build_bom(bom)
|
||||||
|
bom_list_json = json_builder.bom_to_json(bom_list)
|
||||||
|
|
||||||
# 3. Generate DOCUMENTATION PDF file
|
# 3. Generate DOCUMENTATION PDF file
|
||||||
step = 'Generating Documentation'
|
step = 'Generating Documentation'
|
||||||
@@ -84,8 +85,8 @@ def export_to_sfdc(session_id):
|
|||||||
step = 'Uploading to S3'
|
step = 'Uploading to S3'
|
||||||
filename = uuid.uuid4().hex
|
filename = uuid.uuid4().hex
|
||||||
bom_csv_url = s3_upload(io.StringIO(csv_file), filename=filename + '.csv')
|
bom_csv_url = s3_upload(io.StringIO(csv_file), filename=filename + '.csv')
|
||||||
bom_json_url = s3_upload(io.StringIO(json_str), filename=filename + '.json')
|
|
||||||
doc_url = s3_upload(io.BytesIO(document), filename=filename + '.pdf')
|
doc_url = s3_upload(io.BytesIO(document), filename=filename + '.pdf')
|
||||||
|
bom_json_url = s3_upload(io.StringIO(bom_list_json), filename=filename + '.json')
|
||||||
if dxf_contents: # Optional
|
if dxf_contents: # Optional
|
||||||
dxf_url = s3_upload(io.StringIO(dxf_contents), filename=filename + '.dxf')
|
dxf_url = s3_upload(io.StringIO(dxf_contents), filename=filename + '.dxf')
|
||||||
else:
|
else:
|
||||||
@@ -93,26 +94,34 @@ def export_to_sfdc(session_id):
|
|||||||
|
|
||||||
# 6. Notify SFDC system with an API request
|
# 6. Notify SFDC system with an API request
|
||||||
step = 'Notifying SFDC'
|
step = 'Notifying SFDC'
|
||||||
SFDC_API_URL = 'https://localhost:8443/' # FIXME
|
|
||||||
data = {
|
data = {
|
||||||
'dxf_url': dxf_url,
|
'dxfUrl': dxf_url,
|
||||||
'bom_csv_url': bom_csv_url,
|
'bomCsvUrl': bom_csv_url,
|
||||||
'bom_json_url': bom_json_url,
|
'documentationUrl': doc_url,
|
||||||
'documentation_url': doc_url,
|
'bom': bom_list,
|
||||||
|
'helixSessionId': helix_session_id,
|
||||||
|
'SFID': sfid,
|
||||||
}
|
}
|
||||||
print(data)
|
headers = {'Authorization': 'Bearer {}'.format(access_token)}
|
||||||
# result = requests.post(SFDC_API_URL, data=data, timeout=30)
|
SFDC_API_URL = os.getenv('SFDC_API_URL', 'https://sunpower--qa.cs8.my.salesforce.com')
|
||||||
|
url = SFDC_API_URL + '/services/apexrest/v1/HelixRoofDetails'
|
||||||
|
result = requests.post(url, headers=headers, data=data, timeout=30)
|
||||||
# 7. Internal logs
|
# 7. Internal logs
|
||||||
# if result.status_code != 200: # FIXME
|
if result.status_code <= 299:
|
||||||
# print('')
|
print('Sales Force notified successfully for session {}.'.format(helix_session_id))
|
||||||
# else:
|
# print(result.content)
|
||||||
# print('')
|
error = None
|
||||||
|
else:
|
||||||
|
error = 'Helix wasn\'t able to notify the Sales Force ({})'.format(result.status_code)
|
||||||
|
print(error)
|
||||||
|
print(result.content)
|
||||||
|
|
||||||
|
# Only Helix need this information for audit
|
||||||
|
data['bomJsonUrl'] = bom_json_url
|
||||||
|
|
||||||
db_session.close()
|
db_session.close()
|
||||||
return data
|
return error, data
|
||||||
# return result.status_code
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = 'Error while {} for session {}'.format(step, session_id)
|
print('Error while {} for session {}'.format(step, helix_session_id))
|
||||||
print(msg)
|
error = 'Error while {}'.format(step)
|
||||||
raise e
|
return error, {}
|
||||||
|
|||||||
@@ -1,9 +1,24 @@
|
|||||||
{% extends "layout.html.jinja" %}
|
{% extends "layout.html.jinja" %}
|
||||||
{% set title = "Helix Calculator" %}
|
{% set title = "Helix Calculator" %}
|
||||||
{% block contents %}
|
{% block contents %}
|
||||||
{% for warning in context['warning_messages'] %}
|
{% if 'sfdc_export_urls' in context %}
|
||||||
<div class="summary_warning">{{ warning.value }}</div>
|
{% if context['sfdc_export_error'] %}
|
||||||
{% endfor %}
|
<div class="summary_warning" style="margin-top: 20px;">{{ context['sfdc_export_error'] }}</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="msg-container">Documents exported to Sales Force succesffully.</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<ul class="msg-container">
|
||||||
|
{% if context['sfdc_export_urls']['dxfUrl'] %}
|
||||||
|
<li><a href="{{ context['sfdc_export_urls']['dxfUrl'] }}">DXF file</a> (uploaded on Helix)</li>
|
||||||
|
{% else %}
|
||||||
|
<li><a href="{{ context['sfdc_export_urls']['dxfUrlFromSF'] }}">DXF file</a> (uploaded on Sales Force)</li>
|
||||||
|
{% endif %}
|
||||||
|
<li><a href="{{ context['sfdc_export_urls']['documentationUrl'] }}">Documentation file</a></li>
|
||||||
|
<li><a href="{{ context['sfdc_export_urls']['bomCsvUrl'] }}">BOM CSV file</a></li>
|
||||||
|
<li><a href="{{ context['sfdc_export_urls']['bomJsonUrl'] }}">BOM JSON file</a></li>
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="form_section">
|
<div class="form_section">
|
||||||
<h3>Download</h3>
|
<h3>Download</h3>
|
||||||
|
|||||||
Reference in New Issue
Block a user